blob: 5b6077f5eae7e892185825dbe9a579996b0a02c3 [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>
33#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020034#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010035#include <timestamp.h>
36#include <cpu/x86/mtrr.h>
37#include <cpu/intel/speedstep.h>
38#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010039#include <mrc_cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010040
41#include "nehalem.h"
42
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020043#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010044#include <delay.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
1013 info->avg4044[channel] = sum / count;
1014 info->max4048[channel] = max_of_unk;
1015 }
1016}
1017
1018static void jedec_read(struct raminfo *info,
1019 int channel, int slot, int rank,
1020 int total_rank, u8 addr3, unsigned int value)
1021{
1022 /* Handle mirrored mapping. */
1023 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001024 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1025 ((addr3 >> 1) & 0x10);
1026 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1027 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001028
1029 /* Handle mirrored mapping. */
1030 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1031 value =
1032 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1033 << 1);
1034
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001035 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001036
Felix Held04be2dd2018-07-29 04:53:22 +02001037 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1038 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001039
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001040 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001041}
1042
1043enum {
1044 MR1_RZQ12 = 512,
1045 MR1_RZQ2 = 64,
1046 MR1_RZQ4 = 4,
1047 MR1_ODS34OHM = 2
1048};
1049
1050enum {
1051 MR0_BT_INTERLEAVED = 8,
1052 MR0_DLL_RESET_ON = 256
1053};
1054
1055enum {
1056 MR2_RTT_WR_DISABLED = 0,
1057 MR2_RZQ2 = 1 << 10
1058};
1059
1060static void jedec_init(struct raminfo *info)
1061{
1062 int write_recovery;
1063 int channel, slot, rank;
1064 int total_rank;
1065 int dll_on;
1066 int self_refresh_temperature;
1067 int auto_self_refresh;
1068
1069 auto_self_refresh = 1;
1070 self_refresh_temperature = 1;
1071 if (info->board_lane_delay[3] <= 10) {
1072 if (info->board_lane_delay[3] <= 8)
1073 write_recovery = info->board_lane_delay[3] - 4;
1074 else
1075 write_recovery = 5;
1076 } else {
1077 write_recovery = 6;
1078 }
1079 FOR_POPULATED_RANKS {
1080 auto_self_refresh &=
1081 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1082 self_refresh_temperature &=
1083 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1084 }
1085 if (auto_self_refresh == 1)
1086 self_refresh_temperature = 0;
1087
1088 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1089 || (info->populated_ranks[0][0][0]
1090 && info->populated_ranks[0][1][0])
1091 || (info->populated_ranks[1][0][0]
1092 && info->populated_ranks[1][1][0]));
1093
1094 total_rank = 0;
1095
1096 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1097 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1098 int rzq_reg58e;
1099
1100 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1101 rzq_reg58e = 64;
1102 rtt = MR1_RZQ2;
1103 if (info->clock_speed_index != 0) {
1104 rzq_reg58e = 4;
1105 if (info->populated_ranks_mask[channel] == 3)
1106 rtt = MR1_RZQ4;
1107 }
1108 } else {
1109 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1110 rtt = MR1_RZQ12;
1111 rzq_reg58e = 64;
1112 rtt_wr = MR2_RZQ2;
1113 } else {
1114 rzq_reg58e = 4;
1115 rtt = MR1_RZQ4;
1116 }
1117 }
1118
Felix Held04be2dd2018-07-29 04:53:22 +02001119 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1120 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1121 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1122 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1123 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001124
1125 for (slot = 0; slot < NUM_SLOTS; slot++)
1126 for (rank = 0; rank < NUM_RANKS; rank++)
1127 if (info->populated_ranks[channel][slot][rank]) {
1128 jedec_read(info, channel, slot, rank,
1129 total_rank, 0x28,
1130 rtt_wr | (info->
1131 clock_speed_index
1132 << 3)
1133 | (auto_self_refresh << 6) |
1134 (self_refresh_temperature <<
1135 7));
1136 jedec_read(info, channel, slot, rank,
1137 total_rank, 0x38, 0);
1138 jedec_read(info, channel, slot, rank,
1139 total_rank, 0x18,
1140 rtt | MR1_ODS34OHM);
1141 jedec_read(info, channel, slot, rank,
1142 total_rank, 6,
1143 (dll_on << 12) |
1144 (write_recovery << 9)
1145 | ((info->cas_latency - 4) <<
1146 4) | MR0_BT_INTERLEAVED |
1147 MR0_DLL_RESET_ON);
1148 total_rank++;
1149 }
1150 }
1151}
1152
1153static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1154{
1155 unsigned channel, slot, rank;
1156 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1157 unsigned int channel_0_non_interleaved;
1158
1159 FOR_ALL_RANKS {
1160 if (info->populated_ranks[channel][slot][rank]) {
1161 total_mb[channel] +=
1162 pre_jedec ? 256 : (256 << info->
1163 density[channel][slot] >> info->
1164 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001165 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1166 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1167 (info->is_x16_module[channel][slot] |
1168 ((info->density[channel][slot] + 1) << 1))) |
1169 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001170 }
Felix Held04be2dd2018-07-29 04:53:22 +02001171 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1172 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001173 }
1174
1175 info->total_memory_mb = total_mb[0] + total_mb[1];
1176
1177 info->interleaved_part_mb =
1178 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1179 info->non_interleaved_part_mb =
1180 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1181 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001182 MCHBAR32(0x100) = channel_0_non_interleaved |
1183 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001184 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001185 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001186}
1187
1188static void program_board_delay(struct raminfo *info)
1189{
1190 int cas_latency_shift;
1191 int some_delay_ns;
1192 int some_delay_3_half_cycles;
1193
1194 unsigned channel, i;
1195 int high_multiplier;
1196 int lane_3_delay;
1197 int cas_latency_derived;
1198
1199 high_multiplier = 0;
1200 some_delay_ns = 200;
1201 some_delay_3_half_cycles = 4;
1202 cas_latency_shift = info->silicon_revision == 0
1203 || info->silicon_revision == 1 ? 1 : 0;
1204 if (info->revision < 8) {
1205 some_delay_ns = 600;
1206 cas_latency_shift = 0;
1207 }
1208 {
1209 int speed_bit;
1210 speed_bit =
1211 ((info->clock_speed_index > 1
1212 || (info->silicon_revision != 2
1213 && info->silicon_revision != 3))) ^ (info->revision >=
1214 0x10);
1215 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1216 3, 1);
1217 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1218 3, 1);
1219 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1220 && (info->silicon_revision == 2
1221 || info->silicon_revision == 3))
1222 rmw_1d0(0x116, 5, 2, 4, 1);
1223 }
Felix Held04be2dd2018-07-29 04:53:22 +02001224 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1225 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001226
Felix Held04be2dd2018-07-29 04:53:22 +02001227 MCHBAR8(0x124) = info->board_lane_delay[4] +
1228 ((frequency_01(info) + 999) / 1000);
1229 MCHBAR16(0x125) = 0x1360;
1230 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001231 if (info->fsb_frequency < frequency_11(info) / 2) {
1232 unsigned some_delay_2_half_cycles;
1233 high_multiplier = 1;
1234 some_delay_2_half_cycles = ps_to_halfcycles(info,
1235 ((3 *
1236 fsbcycle_ps(info))
1237 >> 1) +
1238 (halfcycle_ps(info)
1239 *
1240 reg178_min[info->
1241 clock_speed_index]
1242 >> 6)
1243 +
1244 4 *
1245 halfcycle_ps(info)
1246 + 2230);
1247 some_delay_3_half_cycles =
1248 min((some_delay_2_half_cycles +
1249 (frequency_11(info) * 2) * (28 -
1250 some_delay_2_half_cycles) /
1251 (frequency_11(info) * 2 -
1252 4 * (info->fsb_frequency))) >> 3, 7);
1253 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001254 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001255 some_delay_3_half_cycles = 3;
1256 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001257 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1258 MCHBAR32(0x224 + (channel << 10)) =
1259 (info->max_slots_used_in_channel - 1) |
1260 ((info->cas_latency - 5 - info->clock_speed_index)
1261 << 21) | ((info->max_slots_used_in_channel +
1262 info->cas_latency - cas_latency_shift - 4) << 16) |
1263 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1264 ((info->cas_latency - info->clock_speed_index +
1265 info->max_slots_used_in_channel - 6) << 8);
1266 MCHBAR32(0x228 + (channel << 10)) =
1267 info->max_slots_used_in_channel;
1268 MCHBAR8(0x239 + (channel << 10)) = 32;
1269 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1270 (some_delay_3_half_cycles << 25) | 0x840000;
1271 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1272 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1273 MCHBAR32(0x24c + (channel << 10)) =
1274 ((!!info->clock_speed_index) << 17) |
1275 (((2 + info->clock_speed_index -
1276 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001277
Felix Held04be2dd2018-07-29 04:53:22 +02001278 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1279 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1280 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001281
1282 write_500(info, channel,
1283 ((!info->populated_ranks[channel][1][1])
1284 | (!info->populated_ranks[channel][1][0] << 1)
1285 | (!info->populated_ranks[channel][0][1] << 2)
1286 | (!info->populated_ranks[channel][0][0] << 3)),
1287 0x4c9, 4, 1);
1288 }
1289
Felix Held22ca8cb2018-07-29 05:09:44 +02001290 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001291 {
1292 u8 freq_divisor = 2;
1293 if (info->fsb_frequency == frequency_11(info))
1294 freq_divisor = 3;
1295 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1296 freq_divisor = 1;
1297 else
1298 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001299 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001300 }
1301
1302 if (info->board_lane_delay[3] <= 10) {
1303 if (info->board_lane_delay[3] <= 8)
1304 lane_3_delay = info->board_lane_delay[3];
1305 else
1306 lane_3_delay = 10;
1307 } else {
1308 lane_3_delay = 12;
1309 }
1310 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1311 if (info->clock_speed_index > 1)
1312 cas_latency_derived++;
1313 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001314 MCHBAR32(0x240 + (channel << 10)) =
1315 ((info->clock_speed_index == 0) * 0x11000) |
1316 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1317 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001318 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1319 0x609, 6, 1);
1320 write_500(info, channel,
1321 info->clock_speed_index + 2 * info->cas_latency - 7,
1322 0x601, 6, 1);
1323
Felix Held04be2dd2018-07-29 04:53:22 +02001324 MCHBAR32(0x250 + (channel << 10)) =
1325 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1326 (info->board_lane_delay[7] << 2) |
1327 (info->board_lane_delay[4] << 16) |
1328 (info->board_lane_delay[1] << 25) |
1329 (info->board_lane_delay[1] << 29) | 1;
1330 MCHBAR32(0x254 + (channel << 10)) =
1331 (info->board_lane_delay[1] >> 3) |
1332 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1333 0x80 | (info->board_lane_delay[6] << 1) |
1334 (info->board_lane_delay[2] << 28) |
1335 (cas_latency_derived << 16) | 0x4700000;
1336 MCHBAR32(0x258 + (channel << 10)) =
1337 ((info->board_lane_delay[5] + info->clock_speed_index +
1338 9) << 12) | ((info->clock_speed_index -
1339 info->cas_latency + 12) << 8) |
1340 (info->board_lane_delay[2] << 17) |
1341 (info->board_lane_delay[4] << 24) | 0x47;
1342 MCHBAR32(0x25c + (channel << 10)) =
1343 (info->board_lane_delay[1] << 1) |
1344 (info->board_lane_delay[0] << 8) | 0x1da50000;
1345 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1346 MCHBAR8(0x5f8 + (channel << 10)) =
1347 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001348 }
1349
1350 program_modules_memory_map(info, 1);
1351
Felix Held04be2dd2018-07-29 04:53:22 +02001352 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1353 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1354 MCHBAR16_OR(0x612, 0x100);
1355 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001356 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001357 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001358 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001359 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001360 }
1361}
1362
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001363#define DEFAULT_PCI_MMIO_SIZE 2048
1364#define HOST_BRIDGE PCI_DEVFN(0, 0)
1365
1366static unsigned int get_mmio_size(void)
1367{
1368 const struct device *dev;
1369 const struct northbridge_intel_nehalem_config *cfg = NULL;
1370
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001371 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001372 if (dev)
1373 cfg = dev->chip_info;
1374
1375 /* If this is zero, it just means devicetree.cb didn't set it */
1376 if (!cfg || cfg->pci_mmio_size == 0)
1377 return DEFAULT_PCI_MMIO_SIZE;
1378 else
1379 return cfg->pci_mmio_size;
1380}
1381
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001382#define BETTER_MEMORY_MAP 0
1383
1384static void program_total_memory_map(struct raminfo *info)
1385{
1386 unsigned int TOM, TOLUD, TOUUD;
1387 unsigned int quickpath_reserved;
1388 unsigned int REMAPbase;
1389 unsigned int uma_base_igd;
1390 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001391 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001392 int memory_remap;
1393 unsigned int memory_map[8];
1394 int i;
1395 unsigned int current_limit;
1396 unsigned int tseg_base;
1397 int uma_size_igd = 0, uma_size_gtt = 0;
1398
1399 memset(memory_map, 0, sizeof(memory_map));
1400
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001402 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 gav(t);
1404 const int uma_sizes_gtt[16] =
1405 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1406 /* Igd memory */
1407 const int uma_sizes_igd[16] = {
1408 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1409 256, 512
1410 };
1411
1412 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1413 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1414 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001416 mmio_size = get_mmio_size();
1417
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418 TOM = info->total_memory_mb;
1419 if (TOM == 4096)
1420 TOM = 4032;
1421 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001422 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001423 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 memory_remap = 0;
1425 if (TOUUD - TOLUD > 64) {
1426 memory_remap = 1;
1427 REMAPbase = max(4096, TOUUD);
1428 TOUUD = TOUUD - TOLUD + 4096;
1429 }
1430 if (TOUUD > 4096)
1431 memory_map[2] = TOUUD | 1;
1432 quickpath_reserved = 0;
1433
1434 {
1435 u32 t;
1436
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001437 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438 if (t & 0x800)
1439 quickpath_reserved =
1440 (1 << find_lowest_bit_set32(t >> 20));
1441 }
1442 if (memory_remap)
1443 TOUUD -= quickpath_reserved;
1444
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 uma_base_igd = TOLUD - uma_size_igd;
1446 uma_base_gtt = uma_base_igd - uma_size_gtt;
1447 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1448 if (!memory_remap)
1449 tseg_base -= quickpath_reserved;
1450 tseg_base = ALIGN_DOWN(tseg_base, 8);
1451
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001452 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1453 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001455 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1456 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459
1460 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001461 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1462 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001464 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465
1466 current_limit = 0;
1467 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1468 memory_map[1] = 4096;
1469 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1470 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001471 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1473 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001474 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001475 }
1476}
1477
1478static void collect_system_info(struct raminfo *info)
1479{
1480 u32 capid0[3];
1481 int i;
1482 unsigned channel;
1483
1484 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001485 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1486 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487
1488 if (!info->heci_bar)
1489 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001490 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001491 if (!info->memory_reserved_for_heci_mb) {
1492 /* Wait for ME to be ready */
1493 intel_early_me_init();
1494 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1495 }
1496
1497 for (i = 0; i < 3; i++)
1498 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001499 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1500 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001501 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1502
1503 if ((capid0[1] >> 11) & 1)
1504 info->uma_enabled = 0;
1505 else
1506 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001507 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001508 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1509 info->silicon_revision = 0;
1510
1511 if (capid0[2] & 2) {
1512 info->silicon_revision = 0;
1513 info->max_supported_clock_speed_index = 2;
1514 for (channel = 0; channel < NUM_CHANNELS; channel++)
1515 if (info->populated_ranks[channel][0][0]
1516 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1517 3) {
1518 info->silicon_revision = 2;
1519 info->max_supported_clock_speed_index = 1;
1520 }
1521 } else {
1522 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1523 case 1:
1524 case 2:
1525 info->silicon_revision = 3;
1526 break;
1527 case 3:
1528 info->silicon_revision = 0;
1529 break;
1530 case 0:
1531 info->silicon_revision = 2;
1532 break;
1533 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001534 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001535 case 0x40:
1536 info->silicon_revision = 0;
1537 break;
1538 case 0x48:
1539 info->silicon_revision = 1;
1540 break;
1541 }
1542 }
1543}
1544
1545static void write_training_data(struct raminfo *info)
1546{
1547 int tm, channel, slot, rank, lane;
1548 if (info->revision < 8)
1549 return;
1550
1551 for (tm = 0; tm < 4; tm++)
1552 for (channel = 0; channel < NUM_CHANNELS; channel++)
1553 for (slot = 0; slot < NUM_SLOTS; slot++)
1554 for (rank = 0; rank < NUM_RANKS; rank++)
1555 for (lane = 0; lane < 9; lane++)
1556 write_500(info, channel,
1557 info->
1558 cached_training->
1559 lane_timings[tm]
1560 [channel][slot][rank]
1561 [lane],
1562 get_timing_register_addr
1563 (lane, tm, slot,
1564 rank), 9, 0);
1565 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1566 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1567}
1568
1569static void dump_timings(struct raminfo *info)
1570{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001571 int channel, slot, rank, lane, i;
Arthur Heymansb3282092019-04-14 17:53:28 +02001572 printk(RAM_DEBUG, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573 FOR_POPULATED_RANKS {
Arthur Heymansb3282092019-04-14 17:53:28 +02001574 printk(RAM_DEBUG, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575 slot, rank);
1576 for (lane = 0; lane < 9; lane++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001577 printk(RAM_DEBUG, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 for (i = 0; i < 4; i++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001579 printk(RAM_DEBUG, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 read_500(info, channel,
1581 get_timing_register_addr
1582 (lane, i, slot, rank),
1583 9),
1584 info->training.
1585 lane_timings[i][channel][slot][rank]
1586 [lane]);
1587 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001588 printk(RAM_DEBUG, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589 }
1590 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001591 printk(RAM_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592 info->training.reg_178);
Arthur Heymansb3282092019-04-14 17:53:28 +02001593 printk(RAM_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001595}
1596
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001597/* Read timings and other registers that need to be restored verbatim and
1598 put them to CBMEM.
1599 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600static void save_timings(struct raminfo *info)
1601{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603 int channel, slot, rank, lane, i;
1604
1605 train = info->training;
1606 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1607 for (i = 0; i < 4; i++)
1608 train.lane_timings[i][channel][slot][rank][lane] =
1609 read_500(info, channel,
1610 get_timing_register_addr(lane, i, slot,
1611 rank), 9);
1612 train.reg_178 = read_1d0(0x178, 7);
1613 train.reg_10b = read_1d0(0x10b, 6);
1614
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001615 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1616 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001617 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001618 train.reg274265[channel][0] = reg32 >> 16;
1619 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001620 train.reg274265[channel][2] =
1621 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001622 }
Felix Held04be2dd2018-07-29 04:53:22 +02001623 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1624 train.reg_6dc = MCHBAR32(0x6dc);
1625 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001626
Arthur Heymansb3282092019-04-14 17:53:28 +02001627 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1628 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001629
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001630 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001631 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1632 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001633}
1634
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001635static const struct ram_training *get_cached_training(void)
1636{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001637 struct region_device rdev;
1638 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1639 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001641 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001642}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643
1644/* FIXME: add timeout. */
1645static void wait_heci_ready(void)
1646{
Felix Held04be2dd2018-07-29 04:53:22 +02001647 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1648 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001649 write32((DEFAULT_HECIBAR + 0x4),
1650 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651}
1652
1653/* FIXME: add timeout. */
1654static void wait_heci_cb_avail(int len)
1655{
1656 union {
1657 struct mei_csr csr;
1658 u32 raw;
1659 } csr;
1660
Felix Held22ca8cb2018-07-29 05:09:44 +02001661 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1662 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663
1664 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001665 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001666 while (len >
1667 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001668 csr.csr.buffer_read_ptr))
1669 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670}
1671
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001672static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673{
1674 int len = (head->length + 3) / 4;
1675 int i;
1676
1677 wait_heci_cb_avail(len + 1);
1678
1679 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001680 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001682 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001683
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001684 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1685 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001686}
1687
1688static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001689send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001690{
1691 struct mei_header head;
1692 int maxlen;
1693
1694 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001695 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696
1697 while (len) {
1698 int cur = len;
1699 if (cur > maxlen) {
1700 cur = maxlen;
1701 head.is_complete = 0;
1702 } else
1703 head.is_complete = 1;
1704 head.length = cur;
1705 head.reserved = 0;
1706 head.client_address = clientaddress;
1707 head.host_address = hostaddress;
1708 send_heci_packet(&head, (u32 *) msg);
1709 len -= cur;
1710 msg += cur;
1711 }
1712}
1713
1714/* FIXME: Add timeout. */
1715static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001716recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1717 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718{
1719 union {
1720 struct mei_csr csr;
1721 u32 raw;
1722 } csr;
1723 int i = 0;
1724
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001725 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001727 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001728 }
Felix Held04be2dd2018-07-29 04:53:22 +02001729 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1730 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001733 write32(DEFAULT_HECIBAR + 0x4,
1734 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735 *packet_size = 0;
1736 return 0;
1737 }
1738 if (head->length + 4 > 4 * csr.csr.buffer_depth
1739 || head->length > *packet_size) {
1740 *packet_size = 0;
1741 return -1;
1742 }
1743
1744 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001745 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001746 while (((head->length + 3) >> 2) >
1747 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1748 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001749
1750 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001751 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001752 *packet_size = head->length;
1753 if (!csr.csr.ready)
1754 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001755 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001756 return 0;
1757}
1758
1759/* FIXME: Add timeout. */
1760static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001761recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001762{
1763 struct mei_header head;
1764 int current_position;
1765
1766 current_position = 0;
1767 while (1) {
1768 u32 current_size;
1769 current_size = *message_size - current_position;
1770 if (recv_heci_packet
1771 (info, &head, message + (current_position >> 2),
1772 &current_size) == -1)
1773 break;
1774 if (!current_size)
1775 break;
1776 current_position += current_size;
1777 if (head.is_complete) {
1778 *message_size = current_position;
1779 return 0;
1780 }
1781
1782 if (current_position >= *message_size)
1783 break;
1784 }
1785 *message_size = 0;
1786 return -1;
1787}
1788
1789static void send_heci_uma_message(struct raminfo *info)
1790{
1791 struct uma_reply {
1792 u8 group_id;
1793 u8 command;
1794 u8 reserved;
1795 u8 result;
1796 u8 field2;
1797 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001798 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001799 struct uma_message {
1800 u8 group_id;
1801 u8 cmd;
1802 u8 reserved;
1803 u8 result;
1804 u32 c2;
1805 u64 heci_uma_addr;
1806 u32 memory_reserved_for_heci_mb;
1807 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001808 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001809 0, MKHI_SET_UMA, 0, 0,
1810 0x82,
1811 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1812 u32 reply_size;
1813
1814 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1815
1816 reply_size = sizeof(reply);
1817 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1818 return;
1819
1820 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1821 die("HECI init failed\n");
1822}
1823
1824static void setup_heci_uma(struct raminfo *info)
1825{
1826 u32 reg44;
1827
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001828 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001829 info->memory_reserved_for_heci_mb = 0;
1830 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001831 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832 return;
1833
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001834 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1836 info->heci_uma_addr =
1837 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001838 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 info->memory_reserved_for_heci_mb)) << 20;
1840
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001841 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001843 write32(DEFAULT_DMIBAR + 0x14,
1844 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1845 write32(DEFAULT_RCBA + 0x14,
1846 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1847 write32(DEFAULT_DMIBAR + 0x20,
1848 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1849 write32(DEFAULT_RCBA + 0x20,
1850 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1851 write32(DEFAULT_DMIBAR + 0x2c,
1852 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1853 write32(DEFAULT_RCBA + 0x30,
1854 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1855 write32(DEFAULT_DMIBAR + 0x38,
1856 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1857 write32(DEFAULT_RCBA + 0x40,
1858 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001860 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1861 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001862 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1863 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1864 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865 }
1866
Felix Held04be2dd2018-07-29 04:53:22 +02001867 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001868
1869 send_heci_uma_message(info);
1870
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001871 pci_write_config32(HECIDEV, 0x10, 0x0);
1872 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001873
1874}
1875
1876static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1877{
1878 int ranks_in_channel;
1879 ranks_in_channel = info->populated_ranks[channel][0][0]
1880 + info->populated_ranks[channel][0][1]
1881 + info->populated_ranks[channel][1][0]
1882 + info->populated_ranks[channel][1][1];
1883
1884 /* empty channel */
1885 if (ranks_in_channel == 0)
1886 return 1;
1887
1888 if (ranks_in_channel != ranks)
1889 return 0;
1890 /* single slot */
1891 if (info->populated_ranks[channel][0][0] !=
1892 info->populated_ranks[channel][1][0])
1893 return 1;
1894 if (info->populated_ranks[channel][0][1] !=
1895 info->populated_ranks[channel][1][1])
1896 return 1;
1897 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1898 return 0;
1899 if (info->density[channel][0] != info->density[channel][1])
1900 return 0;
1901 return 1;
1902}
1903
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001904static void read_4090(struct raminfo *info)
1905{
1906 int i, channel, slot, rank, lane;
1907 for (i = 0; i < 2; i++)
1908 for (slot = 0; slot < NUM_SLOTS; slot++)
1909 for (rank = 0; rank < NUM_RANKS; rank++)
1910 for (lane = 0; lane < 9; lane++)
1911 info->training.
1912 lane_timings[0][i][slot][rank][lane]
1913 = 32;
1914
1915 for (i = 1; i < 4; i++)
1916 for (channel = 0; channel < NUM_CHANNELS; channel++)
1917 for (slot = 0; slot < NUM_SLOTS; slot++)
1918 for (rank = 0; rank < NUM_RANKS; rank++)
1919 for (lane = 0; lane < 9; lane++) {
1920 info->training.
1921 lane_timings[i][channel]
1922 [slot][rank][lane] =
1923 read_500(info, channel,
1924 get_timing_register_addr
1925 (lane, i, slot,
1926 rank), 9)
1927 + (i == 1) * 11; // !!!!
1928 }
1929
1930}
1931
1932static u32 get_etalon2(int flip, u32 addr)
1933{
1934 const u16 invmask[] = {
1935 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1936 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1937 };
1938 u32 ret;
1939 u32 comp4 = addr / 480;
1940 addr %= 480;
1941 u32 comp1 = addr & 0xf;
1942 u32 comp2 = (addr >> 4) & 1;
1943 u32 comp3 = addr >> 5;
1944
1945 if (comp4)
1946 ret = 0x1010101 << (comp4 - 1);
1947 else
1948 ret = 0;
1949 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1950 ret = ~ret;
1951
1952 return ret;
1953}
1954
1955static void disable_cache(void)
1956{
1957 msr_t msr = {.lo = 0, .hi = 0 };
1958
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001959 wrmsr(MTRR_PHYS_BASE(3), msr);
1960 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001961}
1962
1963static void enable_cache(unsigned int base, unsigned int size)
1964{
1965 msr_t msr;
1966 msr.lo = base | MTRR_TYPE_WRPROT;
1967 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001968 wrmsr(MTRR_PHYS_BASE(3), msr);
1969 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970 & 0xffffffff);
1971 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001972 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001973}
1974
1975static void flush_cache(u32 start, u32 size)
1976{
1977 u32 end;
1978 u32 addr;
1979
1980 end = start + (ALIGN_DOWN(size + 4096, 4096));
1981 for (addr = start; addr < end; addr += 64)
1982 clflush(addr);
1983}
1984
1985static void clear_errors(void)
1986{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001987 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001988}
1989
1990static void write_testing(struct raminfo *info, int totalrank, int flip)
1991{
1992 int nwrites = 0;
1993 /* in 8-byte units. */
1994 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001995 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001996
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001997 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001998 for (offset = 0; offset < 9 * 480; offset += 2) {
1999 write32(base + offset * 8, get_etalon2(flip, offset));
2000 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2001 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2002 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2003 nwrites += 4;
2004 if (nwrites >= 320) {
2005 clear_errors();
2006 nwrites = 0;
2007 }
2008 }
2009}
2010
2011static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2012{
2013 u8 failmask = 0;
2014 int i;
2015 int comp1, comp2, comp3;
2016 u32 failxor[2] = { 0, 0 };
2017
2018 enable_cache((total_rank << 28), 1728 * 5 * 4);
2019
2020 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2021 for (comp1 = 0; comp1 < 4; comp1++)
2022 for (comp2 = 0; comp2 < 60; comp2++) {
2023 u32 re[4];
2024 u32 curroffset =
2025 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2026 read128((total_rank << 28) | (curroffset << 3),
2027 (u64 *) re);
2028 failxor[0] |=
2029 get_etalon2(flip, curroffset) ^ re[0];
2030 failxor[1] |=
2031 get_etalon2(flip, curroffset) ^ re[1];
2032 failxor[0] |=
2033 get_etalon2(flip, curroffset | 1) ^ re[2];
2034 failxor[1] |=
2035 get_etalon2(flip, curroffset | 1) ^ re[3];
2036 }
2037 for (i = 0; i < 8; i++)
2038 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2039 failmask |= 1 << i;
2040 }
2041 disable_cache();
2042 flush_cache((total_rank << 28), 1728 * 5 * 4);
2043 return failmask;
2044}
2045
2046const u32 seed1[0x18] = {
2047 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2048 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2049 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2050 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2051 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2052 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2053};
2054
2055static u32 get_seed2(int a, int b)
2056{
2057 const u32 seed2[5] = {
2058 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2059 0x5b6db6db,
2060 };
2061 u32 r;
2062 r = seed2[(a + (a >= 10)) / 5];
2063 return b ? ~r : r;
2064}
2065
2066static int make_shift(int comp2, int comp5, int x)
2067{
2068 const u8 seed3[32] = {
2069 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2070 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2071 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2072 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2073 };
2074
2075 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2076}
2077
2078static u32 get_etalon(int flip, u32 addr)
2079{
2080 u32 mask_byte = 0;
2081 int comp1 = (addr >> 1) & 1;
2082 int comp2 = (addr >> 3) & 0x1f;
2083 int comp3 = (addr >> 8) & 0xf;
2084 int comp4 = (addr >> 12) & 0xf;
2085 int comp5 = (addr >> 16) & 0x1f;
2086 u32 mask_bit = ~(0x10001 << comp3);
2087 u32 part1;
2088 u32 part2;
2089 int byte;
2090
2091 part2 =
2092 ((seed1[comp5] >>
2093 make_shift(comp2, comp5,
2094 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2095 part1 =
2096 ((seed1[comp5] >>
2097 make_shift(comp2, comp5,
2098 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2099
2100 for (byte = 0; byte < 4; byte++)
2101 if ((get_seed2(comp5, comp4) >>
2102 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2103 mask_byte |= 0xff << (8 * byte);
2104
2105 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2106 (comp3 + 16));
2107}
2108
2109static void
2110write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2111 char flip)
2112{
2113 int i;
2114 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002115 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2116 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002117}
2118
2119static u8
2120check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2121 char flip)
2122{
2123 u8 failmask = 0;
2124 u32 failxor[2];
2125 int i;
2126 int comp1, comp2, comp3;
2127
2128 failxor[0] = 0;
2129 failxor[1] = 0;
2130
2131 enable_cache(totalrank << 28, 134217728);
2132 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2133 for (comp1 = 0; comp1 < 16; comp1++)
2134 for (comp2 = 0; comp2 < 64; comp2++) {
2135 u32 addr =
2136 (totalrank << 28) | (region << 25) | (block
2137 << 16)
2138 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2139 2);
2140 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002141 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002142 }
2143 for (i = 0; i < 8; i++)
2144 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2145 failmask |= 1 << i;
2146 }
2147 disable_cache();
2148 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2149 return failmask;
2150}
2151
2152static int check_bounded(unsigned short *vals, u16 bound)
2153{
2154 int i;
2155
2156 for (i = 0; i < 8; i++)
2157 if (vals[i] < bound)
2158 return 0;
2159 return 1;
2160}
2161
2162enum state {
2163 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2164};
2165
2166static int validate_state(enum state *in)
2167{
2168 int i;
2169 for (i = 0; i < 8; i++)
2170 if (in[i] != COMPLETE)
2171 return 0;
2172 return 1;
2173}
2174
2175static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002176do_fsm(enum state *state, u16 *counter,
2177 u8 fail_mask, int margin, int uplimit,
2178 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002179{
2180 int lane;
2181
2182 for (lane = 0; lane < 8; lane++) {
2183 int is_fail = (fail_mask >> lane) & 1;
2184 switch (state[lane]) {
2185 case BEFORE_USABLE:
2186 if (!is_fail) {
2187 counter[lane] = 1;
2188 state[lane] = AT_USABLE;
2189 break;
2190 }
2191 counter[lane] = 0;
2192 state[lane] = BEFORE_USABLE;
2193 break;
2194 case AT_USABLE:
2195 if (!is_fail) {
2196 ++counter[lane];
2197 if (counter[lane] >= margin) {
2198 state[lane] = AT_MARGIN;
2199 res_low[lane] = val - margin + 1;
2200 break;
2201 }
2202 state[lane] = 1;
2203 break;
2204 }
2205 counter[lane] = 0;
2206 state[lane] = BEFORE_USABLE;
2207 break;
2208 case AT_MARGIN:
2209 if (is_fail) {
2210 state[lane] = COMPLETE;
2211 res_high[lane] = val - 1;
2212 } else {
2213 counter[lane]++;
2214 state[lane] = AT_MARGIN;
2215 if (val == uplimit) {
2216 state[lane] = COMPLETE;
2217 res_high[lane] = uplimit;
2218 }
2219 }
2220 break;
2221 case COMPLETE:
2222 break;
2223 }
2224 }
2225}
2226
2227static void
2228train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2229 u8 total_rank, u8 reg_178, int first_run, int niter,
2230 timing_bounds_t * timings)
2231{
2232 int lane;
2233 enum state state[8];
2234 u16 count[8];
2235 u8 lower_usable[8];
2236 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002237 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002238 u8 secondary_total_rank;
2239 u8 reg1b3;
2240
2241 if (info->populated_ranks_mask[1]) {
2242 if (channel == 1)
2243 secondary_total_rank =
2244 info->populated_ranks[1][0][0] +
2245 info->populated_ranks[1][0][1]
2246 + info->populated_ranks[1][1][0] +
2247 info->populated_ranks[1][1][1];
2248 else
2249 secondary_total_rank = 0;
2250 } else
2251 secondary_total_rank = total_rank;
2252
2253 {
2254 int i;
2255 for (i = 0; i < 8; i++)
2256 state[i] = BEFORE_USABLE;
2257 }
2258
2259 if (!first_run) {
2260 int is_all_ok = 1;
2261 for (lane = 0; lane < 8; lane++)
2262 if (timings[reg_178][channel][slot][rank][lane].
2263 smallest ==
2264 timings[reg_178][channel][slot][rank][lane].
2265 largest) {
2266 timings[reg_178][channel][slot][rank][lane].
2267 smallest = 0;
2268 timings[reg_178][channel][slot][rank][lane].
2269 largest = 0;
2270 is_all_ok = 0;
2271 }
2272 if (is_all_ok) {
2273 int i;
2274 for (i = 0; i < 8; i++)
2275 state[i] = COMPLETE;
2276 }
2277 }
2278
2279 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2280 u8 failmask = 0;
2281 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2282 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2283 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002284 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002285 do_fsm(state, count, failmask, 5, 47, lower_usable,
2286 upper_usable, reg1b3);
2287 }
2288
2289 if (reg1b3) {
2290 write_1d0(0, 0x1b3, 6, 1);
2291 write_1d0(0, 0x1a3, 6, 1);
2292 for (lane = 0; lane < 8; lane++) {
2293 if (state[lane] == COMPLETE) {
2294 timings[reg_178][channel][slot][rank][lane].
2295 smallest =
2296 lower_usable[lane] +
2297 (info->training.
2298 lane_timings[0][channel][slot][rank][lane]
2299 & 0x3F) - 32;
2300 timings[reg_178][channel][slot][rank][lane].
2301 largest =
2302 upper_usable[lane] +
2303 (info->training.
2304 lane_timings[0][channel][slot][rank][lane]
2305 & 0x3F) - 32;
2306 }
2307 }
2308 }
2309
2310 if (!first_run) {
2311 for (lane = 0; lane < 8; lane++)
2312 if (state[lane] == COMPLETE) {
2313 write_500(info, channel,
2314 timings[reg_178][channel][slot][rank]
2315 [lane].smallest,
2316 get_timing_register_addr(lane, 0,
2317 slot, rank),
2318 9, 1);
2319 write_500(info, channel,
2320 timings[reg_178][channel][slot][rank]
2321 [lane].smallest +
2322 info->training.
2323 lane_timings[1][channel][slot][rank]
2324 [lane]
2325 -
2326 info->training.
2327 lane_timings[0][channel][slot][rank]
2328 [lane], get_timing_register_addr(lane,
2329 1,
2330 slot,
2331 rank),
2332 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002333 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002335 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002336
2337 do {
2338 u8 failmask = 0;
2339 int i;
2340 for (i = 0; i < niter; i++) {
2341 if (failmask == 0xFF)
2342 break;
2343 failmask |=
2344 check_testing_type2(info, total_rank, 2, i,
2345 0);
2346 failmask |=
2347 check_testing_type2(info, total_rank, 3, i,
2348 1);
2349 }
Felix Held04be2dd2018-07-29 04:53:22 +02002350 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002351 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002352 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002353 if ((1 << lane) & failmask) {
2354 if (timings[reg_178][channel]
2355 [slot][rank][lane].
2356 largest <=
2357 timings[reg_178][channel]
2358 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002359 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002360 [lane] = -1;
2361 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002362 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363 [lane] = 0;
2364 timings[reg_178]
2365 [channel][slot]
2366 [rank][lane].
2367 smallest++;
2368 write_500(info, channel,
2369 timings
2370 [reg_178]
2371 [channel]
2372 [slot][rank]
2373 [lane].
2374 smallest,
2375 get_timing_register_addr
2376 (lane, 0,
2377 slot, rank),
2378 9, 1);
2379 write_500(info, channel,
2380 timings
2381 [reg_178]
2382 [channel]
2383 [slot][rank]
2384 [lane].
2385 smallest +
2386 info->
2387 training.
2388 lane_timings
2389 [1][channel]
2390 [slot][rank]
2391 [lane]
2392 -
2393 info->
2394 training.
2395 lane_timings
2396 [0][channel]
2397 [slot][rank]
2398 [lane],
2399 get_timing_register_addr
2400 (lane, 1,
2401 slot, rank),
2402 9, 1);
2403 }
2404 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002405 num_successfully_checked[lane]
2406 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002407 }
2408 }
Felix Held04be2dd2018-07-29 04:53:22 +02002409 while (!check_bounded(num_successfully_checked, 2))
2410 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002411
2412 for (lane = 0; lane < 8; lane++)
2413 if (state[lane] == COMPLETE) {
2414 write_500(info, channel,
2415 timings[reg_178][channel][slot][rank]
2416 [lane].largest,
2417 get_timing_register_addr(lane, 0,
2418 slot, rank),
2419 9, 1);
2420 write_500(info, channel,
2421 timings[reg_178][channel][slot][rank]
2422 [lane].largest +
2423 info->training.
2424 lane_timings[1][channel][slot][rank]
2425 [lane]
2426 -
2427 info->training.
2428 lane_timings[0][channel][slot][rank]
2429 [lane], get_timing_register_addr(lane,
2430 1,
2431 slot,
2432 rank),
2433 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002434 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002435 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002436 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002437
2438 do {
2439 int failmask = 0;
2440 int i;
2441 for (i = 0; i < niter; i++) {
2442 if (failmask == 0xFF)
2443 break;
2444 failmask |=
2445 check_testing_type2(info, total_rank, 2, i,
2446 0);
2447 failmask |=
2448 check_testing_type2(info, total_rank, 3, i,
2449 1);
2450 }
2451
Felix Held04be2dd2018-07-29 04:53:22 +02002452 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002453 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002454 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002455 if ((1 << lane) & failmask) {
2456 if (timings[reg_178][channel]
2457 [slot][rank][lane].
2458 largest <=
2459 timings[reg_178][channel]
2460 [slot][rank][lane].
2461 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002462 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002463 [lane] = -1;
2464 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002465 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002466 [lane] = 0;
2467 timings[reg_178]
2468 [channel][slot]
2469 [rank][lane].
2470 largest--;
2471 write_500(info, channel,
2472 timings
2473 [reg_178]
2474 [channel]
2475 [slot][rank]
2476 [lane].
2477 largest,
2478 get_timing_register_addr
2479 (lane, 0,
2480 slot, rank),
2481 9, 1);
2482 write_500(info, channel,
2483 timings
2484 [reg_178]
2485 [channel]
2486 [slot][rank]
2487 [lane].
2488 largest +
2489 info->
2490 training.
2491 lane_timings
2492 [1][channel]
2493 [slot][rank]
2494 [lane]
2495 -
2496 info->
2497 training.
2498 lane_timings
2499 [0][channel]
2500 [slot][rank]
2501 [lane],
2502 get_timing_register_addr
2503 (lane, 1,
2504 slot, rank),
2505 9, 1);
2506 }
2507 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002508 num_successfully_checked[lane]
2509 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002510 }
2511 }
2512 }
Felix Held04be2dd2018-07-29 04:53:22 +02002513 while (!check_bounded(num_successfully_checked, 3))
2514 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002515
2516 for (lane = 0; lane < 8; lane++) {
2517 write_500(info, channel,
2518 info->training.
2519 lane_timings[0][channel][slot][rank][lane],
2520 get_timing_register_addr(lane, 0, slot, rank),
2521 9, 1);
2522 write_500(info, channel,
2523 info->training.
2524 lane_timings[1][channel][slot][rank][lane],
2525 get_timing_register_addr(lane, 1, slot, rank),
2526 9, 1);
2527 if (timings[reg_178][channel][slot][rank][lane].
2528 largest <=
2529 timings[reg_178][channel][slot][rank][lane].
2530 smallest) {
2531 timings[reg_178][channel][slot][rank][lane].
2532 largest = 0;
2533 timings[reg_178][channel][slot][rank][lane].
2534 smallest = 0;
2535 }
2536 }
2537 }
2538}
2539
2540static void set_10b(struct raminfo *info, u8 val)
2541{
2542 int channel;
2543 int slot, rank;
2544 int lane;
2545
2546 if (read_1d0(0x10b, 6) == val)
2547 return;
2548
2549 write_1d0(val, 0x10b, 6, 1);
2550
2551 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2552 u16 reg_500;
2553 reg_500 = read_500(info, channel,
2554 get_timing_register_addr(lane, 0, slot,
2555 rank), 9);
2556 if (val == 1) {
2557 if (lut16[info->clock_speed_index] <= reg_500)
2558 reg_500 -= lut16[info->clock_speed_index];
2559 else
2560 reg_500 = 0;
2561 } else {
2562 reg_500 += lut16[info->clock_speed_index];
2563 }
2564 write_500(info, channel, reg_500,
2565 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2566 }
2567}
2568
2569static void set_ecc(int onoff)
2570{
2571 int channel;
2572 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2573 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002574 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002575 if (onoff)
2576 t |= 1;
2577 else
2578 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002579 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002580 }
2581}
2582
2583static void set_178(u8 val)
2584{
2585 if (val >= 31)
2586 val = val - 31;
2587 else
2588 val = 63 - val;
2589
2590 write_1d0(2 * val, 0x178, 7, 1);
2591}
2592
2593static void
2594write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2595 int type)
2596{
2597 int lane;
2598
2599 for (lane = 0; lane < 8; lane++)
2600 write_500(info, channel,
2601 info->training.
2602 lane_timings[type][channel][slot][rank][lane],
2603 get_timing_register_addr(lane, type, slot, rank), 9,
2604 0);
2605}
2606
2607static void
2608try_timing_offsets(struct raminfo *info, int channel,
2609 int slot, int rank, int totalrank)
2610{
2611 u16 count[8];
2612 enum state state[8];
2613 u8 lower_usable[8], upper_usable[8];
2614 int lane;
2615 int i;
2616 int flip = 1;
2617 int timing_offset;
2618
2619 for (i = 0; i < 8; i++)
2620 state[i] = BEFORE_USABLE;
2621
2622 memset(count, 0, sizeof(count));
2623
2624 for (lane = 0; lane < 8; lane++)
2625 write_500(info, channel,
2626 info->training.
2627 lane_timings[2][channel][slot][rank][lane] + 32,
2628 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2629
2630 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2631 timing_offset++) {
2632 u8 failmask;
2633 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2634 failmask = 0;
2635 for (i = 0; i < 2 && failmask != 0xff; i++) {
2636 flip = !flip;
2637 write_testing(info, totalrank, flip);
2638 failmask |= check_testing(info, totalrank, flip);
2639 }
2640 do_fsm(state, count, failmask, 10, 63, lower_usable,
2641 upper_usable, timing_offset);
2642 }
2643 write_1d0(0, 0x1bb, 6, 1);
2644 dump_timings(info);
2645 if (!validate_state(state))
2646 die("Couldn't discover DRAM timings (1)\n");
2647
2648 for (lane = 0; lane < 8; lane++) {
2649 u8 bias = 0;
2650
2651 if (info->silicon_revision) {
2652 int usable_length;
2653
2654 usable_length = upper_usable[lane] - lower_usable[lane];
2655 if (usable_length >= 20) {
2656 bias = usable_length / 2 - 10;
2657 if (bias >= 2)
2658 bias = 2;
2659 }
2660 }
2661 write_500(info, channel,
2662 info->training.
2663 lane_timings[2][channel][slot][rank][lane] +
2664 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2665 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2666 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2667 info->training.lane_timings[2][channel][slot][rank][lane] +
2668 lower_usable[lane];
2669 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2670 info->training.lane_timings[2][channel][slot][rank][lane] +
2671 upper_usable[lane];
2672 info->training.timing2_offset[channel][slot][rank][lane] =
2673 info->training.lane_timings[2][channel][slot][rank][lane];
2674 }
2675}
2676
2677static u8
2678choose_training(struct raminfo *info, int channel, int slot, int rank,
2679 int lane, timing_bounds_t * timings, u8 center_178)
2680{
2681 u16 central_weight;
2682 u16 side_weight;
2683 unsigned int sum = 0, count = 0;
2684 u8 span;
2685 u8 lower_margin, upper_margin;
2686 u8 reg_178;
2687 u8 result;
2688
2689 span = 12;
2690 central_weight = 20;
2691 side_weight = 20;
2692 if (info->silicon_revision == 1 && channel == 1) {
2693 central_weight = 5;
2694 side_weight = 20;
2695 if ((info->
2696 populated_ranks_mask[1] ^ (info->
2697 populated_ranks_mask[1] >> 2)) &
2698 1)
2699 span = 18;
2700 }
2701 if ((info->populated_ranks_mask[0] & 5) == 5) {
2702 central_weight = 20;
2703 side_weight = 20;
2704 }
2705 if (info->clock_speed_index >= 2
2706 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2707 if (info->silicon_revision == 1) {
2708 switch (channel) {
2709 case 0:
2710 if (lane == 1) {
2711 central_weight = 10;
2712 side_weight = 20;
2713 }
2714 break;
2715 case 1:
2716 if (lane == 6) {
2717 side_weight = 5;
2718 central_weight = 20;
2719 }
2720 break;
2721 }
2722 }
2723 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2724 side_weight = 5;
2725 central_weight = 20;
2726 }
2727 }
2728 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2729 reg_178 += span) {
2730 u8 smallest;
2731 u8 largest;
2732 largest = timings[reg_178][channel][slot][rank][lane].largest;
2733 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2734 if (largest - smallest + 1 >= 5) {
2735 unsigned int weight;
2736 if (reg_178 == center_178)
2737 weight = central_weight;
2738 else
2739 weight = side_weight;
2740 sum += weight * (largest + smallest);
2741 count += weight;
2742 }
2743 }
2744 dump_timings(info);
2745 if (count == 0)
2746 die("Couldn't discover DRAM timings (2)\n");
2747 result = sum / (2 * count);
2748 lower_margin =
2749 result - timings[center_178][channel][slot][rank][lane].smallest;
2750 upper_margin =
2751 timings[center_178][channel][slot][rank][lane].largest - result;
2752 if (upper_margin < 10 && lower_margin > 10)
2753 result -= min(lower_margin - 10, 10 - upper_margin);
2754 if (upper_margin > 10 && lower_margin < 10)
2755 result += min(upper_margin - 10, 10 - lower_margin);
2756 return result;
2757}
2758
2759#define STANDARD_MIN_MARGIN 5
2760
2761static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2762{
2763 u16 margin[64];
2764 int lane, rank, slot, channel;
2765 u8 reg178;
2766 int count = 0, sum = 0;
2767
2768 for (reg178 = reg178_min[info->clock_speed_index];
2769 reg178 < reg178_max[info->clock_speed_index];
2770 reg178 += reg178_step[info->clock_speed_index]) {
2771 margin[reg178] = -1;
2772 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2773 int curmargin =
2774 timings[reg178][channel][slot][rank][lane].largest -
2775 timings[reg178][channel][slot][rank][lane].
2776 smallest + 1;
2777 if (curmargin < margin[reg178])
2778 margin[reg178] = curmargin;
2779 }
2780 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2781 u16 weight;
2782 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2783 sum += weight * reg178;
2784 count += weight;
2785 }
2786 }
2787 dump_timings(info);
2788 if (count == 0)
2789 die("Couldn't discover DRAM timings (3)\n");
2790
2791 u8 threshold;
2792
2793 for (threshold = 30; threshold >= 5; threshold--) {
2794 int usable_length = 0;
2795 int smallest_fount = 0;
2796 for (reg178 = reg178_min[info->clock_speed_index];
2797 reg178 < reg178_max[info->clock_speed_index];
2798 reg178 += reg178_step[info->clock_speed_index])
2799 if (margin[reg178] >= threshold) {
2800 usable_length +=
2801 reg178_step[info->clock_speed_index];
2802 info->training.reg178_largest =
2803 reg178 -
2804 2 * reg178_step[info->clock_speed_index];
2805
2806 if (!smallest_fount) {
2807 smallest_fount = 1;
2808 info->training.reg178_smallest =
2809 reg178 +
2810 reg178_step[info->
2811 clock_speed_index];
2812 }
2813 }
2814 if (usable_length >= 0x21)
2815 break;
2816 }
2817
2818 return sum / count;
2819}
2820
2821static int check_cached_sanity(struct raminfo *info)
2822{
2823 int lane;
2824 int slot, rank;
2825 int channel;
2826
2827 if (!info->cached_training)
2828 return 0;
2829
2830 for (channel = 0; channel < NUM_CHANNELS; channel++)
2831 for (slot = 0; slot < NUM_SLOTS; slot++)
2832 for (rank = 0; rank < NUM_RANKS; rank++)
2833 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2834 u16 cached_value, estimation_value;
2835 cached_value =
2836 info->cached_training->
2837 lane_timings[1][channel][slot][rank]
2838 [lane];
2839 if (cached_value >= 0x18
2840 && cached_value <= 0x1E7) {
2841 estimation_value =
2842 info->training.
2843 lane_timings[1][channel]
2844 [slot][rank][lane];
2845 if (estimation_value <
2846 cached_value - 24)
2847 return 0;
2848 if (estimation_value >
2849 cached_value + 24)
2850 return 0;
2851 }
2852 }
2853 return 1;
2854}
2855
2856static int try_cached_training(struct raminfo *info)
2857{
2858 u8 saved_243[2];
2859 u8 tm;
2860
2861 int channel, slot, rank, lane;
2862 int flip = 1;
2863 int i, j;
2864
2865 if (!check_cached_sanity(info))
2866 return 0;
2867
2868 info->training.reg178_center = info->cached_training->reg178_center;
2869 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2870 info->training.reg178_largest = info->cached_training->reg178_largest;
2871 memcpy(&info->training.timing_bounds,
2872 &info->cached_training->timing_bounds,
2873 sizeof(info->training.timing_bounds));
2874 memcpy(&info->training.timing_offset,
2875 &info->cached_training->timing_offset,
2876 sizeof(info->training.timing_offset));
2877
2878 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002879 saved_243[0] = MCHBAR8(0x243);
2880 saved_243[1] = MCHBAR8(0x643);
2881 MCHBAR8(0x243) = saved_243[0] | 2;
2882 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002883 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002884 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002885 if (read_1d0(0x10b, 6) & 1)
2886 set_10b(info, 0);
2887 for (tm = 0; tm < 2; tm++) {
2888 int totalrank;
2889
2890 set_178(tm ? info->cached_training->reg178_largest : info->
2891 cached_training->reg178_smallest);
2892
2893 totalrank = 0;
2894 /* Check timing ranges. With i == 0 we check smallest one and with
2895 i == 1 the largest bound. With j == 0 we check that on the bound
2896 it still works whereas with j == 1 we check that just outside of
2897 bound we fail.
2898 */
2899 FOR_POPULATED_RANKS_BACKWARDS {
2900 for (i = 0; i < 2; i++) {
2901 for (lane = 0; lane < 8; lane++) {
2902 write_500(info, channel,
2903 info->cached_training->
2904 timing2_bounds[channel][slot]
2905 [rank][lane][i],
2906 get_timing_register_addr(lane,
2907 3,
2908 slot,
2909 rank),
2910 9, 1);
2911
2912 if (!i)
2913 write_500(info, channel,
2914 info->
2915 cached_training->
2916 timing2_offset
2917 [channel][slot][rank]
2918 [lane],
2919 get_timing_register_addr
2920 (lane, 2, slot, rank),
2921 9, 1);
2922 write_500(info, channel,
2923 i ? info->cached_training->
2924 timing_bounds[tm][channel]
2925 [slot][rank][lane].
2926 largest : info->
2927 cached_training->
2928 timing_bounds[tm][channel]
2929 [slot][rank][lane].smallest,
2930 get_timing_register_addr(lane,
2931 0,
2932 slot,
2933 rank),
2934 9, 1);
2935 write_500(info, channel,
2936 info->cached_training->
2937 timing_offset[channel][slot]
2938 [rank][lane] +
2939 (i ? info->cached_training->
2940 timing_bounds[tm][channel]
2941 [slot][rank][lane].
2942 largest : info->
2943 cached_training->
2944 timing_bounds[tm][channel]
2945 [slot][rank][lane].
2946 smallest) - 64,
2947 get_timing_register_addr(lane,
2948 1,
2949 slot,
2950 rank),
2951 9, 1);
2952 }
2953 for (j = 0; j < 2; j++) {
2954 u8 failmask;
2955 u8 expected_failmask;
2956 char reg1b3;
2957
2958 reg1b3 = (j == 1) + 4;
2959 reg1b3 =
2960 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2961 write_1d0(reg1b3, 0x1bb, 6, 1);
2962 write_1d0(reg1b3, 0x1b3, 6, 1);
2963 write_1d0(reg1b3, 0x1a3, 6, 1);
2964
2965 flip = !flip;
2966 write_testing(info, totalrank, flip);
2967 failmask =
2968 check_testing(info, totalrank,
2969 flip);
2970 expected_failmask =
2971 j == 0 ? 0x00 : 0xff;
2972 if (failmask != expected_failmask)
2973 goto fail;
2974 }
2975 }
2976 totalrank++;
2977 }
2978 }
2979
2980 set_178(info->cached_training->reg178_center);
2981 if (info->use_ecc)
2982 set_ecc(1);
2983 write_training_data(info);
2984 write_1d0(0, 322, 3, 1);
2985 info->training = *info->cached_training;
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 1;
2994
2995fail:
2996 FOR_POPULATED_RANKS {
2997 write_500_timings_type(info, channel, slot, rank, 1);
2998 write_500_timings_type(info, channel, slot, rank, 2);
2999 write_500_timings_type(info, channel, slot, rank, 3);
3000 }
3001
3002 write_1d0(0, 0x1bb, 6, 1);
3003 write_1d0(0, 0x1b3, 6, 1);
3004 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003005 MCHBAR8(0x243) = saved_243[0];
3006 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003007
3008 return 0;
3009}
3010
3011static void do_ram_training(struct raminfo *info)
3012{
3013 u8 saved_243[2];
3014 int totalrank = 0;
3015 u8 reg_178;
3016 int niter;
3017
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003018 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003019 int lane, rank, slot, channel;
3020 u8 reg178_center;
3021
3022 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003023 saved_243[0] = MCHBAR8(0x243);
3024 saved_243[1] = MCHBAR8(0x643);
3025 MCHBAR8(0x243) = saved_243[0] | 2;
3026 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003027 switch (info->clock_speed_index) {
3028 case 0:
3029 niter = 5;
3030 break;
3031 case 1:
3032 niter = 10;
3033 break;
3034 default:
3035 niter = 19;
3036 break;
3037 }
3038 set_ecc(0);
3039
3040 FOR_POPULATED_RANKS_BACKWARDS {
3041 int i;
3042
3043 write_500_timings_type(info, channel, slot, rank, 0);
3044
3045 write_testing(info, totalrank, 0);
3046 for (i = 0; i < niter; i++) {
3047 write_testing_type2(info, totalrank, 2, i, 0);
3048 write_testing_type2(info, totalrank, 3, i, 1);
3049 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003050 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003051 totalrank++;
3052 }
3053
3054 if (reg178_min[info->clock_speed_index] <
3055 reg178_max[info->clock_speed_index])
3056 memset(timings[reg178_min[info->clock_speed_index]], 0,
3057 sizeof(timings[0]) *
3058 (reg178_max[info->clock_speed_index] -
3059 reg178_min[info->clock_speed_index]));
3060 for (reg_178 = reg178_min[info->clock_speed_index];
3061 reg_178 < reg178_max[info->clock_speed_index];
3062 reg_178 += reg178_step[info->clock_speed_index]) {
3063 totalrank = 0;
3064 set_178(reg_178);
3065 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3066 for (slot = 0; slot < NUM_SLOTS; slot++)
3067 for (rank = 0; rank < NUM_RANKS; rank++) {
3068 memset(&timings[reg_178][channel][slot]
3069 [rank][0].smallest, 0, 16);
3070 if (info->
3071 populated_ranks[channel][slot]
3072 [rank]) {
3073 train_ram_at_178(info, channel,
3074 slot, rank,
3075 totalrank,
3076 reg_178, 1,
3077 niter,
3078 timings);
3079 totalrank++;
3080 }
3081 }
3082 }
3083
3084 reg178_center = choose_reg178(info, timings);
3085
3086 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3087 info->training.timing_bounds[0][channel][slot][rank][lane].
3088 smallest =
3089 timings[info->training.
3090 reg178_smallest][channel][slot][rank][lane].
3091 smallest;
3092 info->training.timing_bounds[0][channel][slot][rank][lane].
3093 largest =
3094 timings[info->training.
3095 reg178_smallest][channel][slot][rank][lane].largest;
3096 info->training.timing_bounds[1][channel][slot][rank][lane].
3097 smallest =
3098 timings[info->training.
3099 reg178_largest][channel][slot][rank][lane].smallest;
3100 info->training.timing_bounds[1][channel][slot][rank][lane].
3101 largest =
3102 timings[info->training.
3103 reg178_largest][channel][slot][rank][lane].largest;
3104 info->training.timing_offset[channel][slot][rank][lane] =
3105 info->training.lane_timings[1][channel][slot][rank][lane]
3106 -
3107 info->training.lane_timings[0][channel][slot][rank][lane] +
3108 64;
3109 }
3110
3111 if (info->silicon_revision == 1
3112 && (info->
3113 populated_ranks_mask[1] ^ (info->
3114 populated_ranks_mask[1] >> 2)) & 1) {
3115 int ranks_after_channel1;
3116
3117 totalrank = 0;
3118 for (reg_178 = reg178_center - 18;
3119 reg_178 <= reg178_center + 18; reg_178 += 18) {
3120 totalrank = 0;
3121 set_178(reg_178);
3122 for (slot = 0; slot < NUM_SLOTS; slot++)
3123 for (rank = 0; rank < NUM_RANKS; rank++) {
3124 if (info->
3125 populated_ranks[1][slot][rank]) {
3126 train_ram_at_178(info, 1, slot,
3127 rank,
3128 totalrank,
3129 reg_178, 0,
3130 niter,
3131 timings);
3132 totalrank++;
3133 }
3134 }
3135 }
3136 ranks_after_channel1 = totalrank;
3137
3138 for (reg_178 = reg178_center - 12;
3139 reg_178 <= reg178_center + 12; reg_178 += 12) {
3140 totalrank = ranks_after_channel1;
3141 set_178(reg_178);
3142 for (slot = 0; slot < NUM_SLOTS; slot++)
3143 for (rank = 0; rank < NUM_RANKS; rank++)
3144 if (info->
3145 populated_ranks[0][slot][rank]) {
3146 train_ram_at_178(info, 0, slot,
3147 rank,
3148 totalrank,
3149 reg_178, 0,
3150 niter,
3151 timings);
3152 totalrank++;
3153 }
3154
3155 }
3156 } else {
3157 for (reg_178 = reg178_center - 12;
3158 reg_178 <= reg178_center + 12; reg_178 += 12) {
3159 totalrank = 0;
3160 set_178(reg_178);
3161 FOR_POPULATED_RANKS_BACKWARDS {
3162 train_ram_at_178(info, channel, slot, rank,
3163 totalrank, reg_178, 0, niter,
3164 timings);
3165 totalrank++;
3166 }
3167 }
3168 }
3169
3170 set_178(reg178_center);
3171 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3172 u16 tm0;
3173
3174 tm0 =
3175 choose_training(info, channel, slot, rank, lane, timings,
3176 reg178_center);
3177 write_500(info, channel, tm0,
3178 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3179 write_500(info, channel,
3180 tm0 +
3181 info->training.
3182 lane_timings[1][channel][slot][rank][lane] -
3183 info->training.
3184 lane_timings[0][channel][slot][rank][lane],
3185 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3186 }
3187
3188 totalrank = 0;
3189 FOR_POPULATED_RANKS_BACKWARDS {
3190 try_timing_offsets(info, channel, slot, rank, totalrank);
3191 totalrank++;
3192 }
Felix Held04be2dd2018-07-29 04:53:22 +02003193 MCHBAR8(0x243) = saved_243[0];
3194 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195 write_1d0(0, 0x142, 3, 1);
3196 info->training.reg178_center = reg178_center;
3197}
3198
3199static void ram_training(struct raminfo *info)
3200{
3201 u16 saved_fc4;
3202
Felix Held04be2dd2018-07-29 04:53:22 +02003203 saved_fc4 = MCHBAR16(0xfc4);
3204 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003205
3206 if (info->revision >= 8)
3207 read_4090(info);
3208
3209 if (!try_cached_training(info))
3210 do_ram_training(info);
3211 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3212 && info->clock_speed_index < 2)
3213 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003214 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003215}
3216
3217static unsigned gcd(unsigned a, unsigned b)
3218{
3219 unsigned t;
3220 if (a > b) {
3221 t = a;
3222 a = b;
3223 b = t;
3224 }
3225 /* invariant a < b. */
3226 while (a) {
3227 t = b % a;
3228 b = a;
3229 a = t;
3230 }
3231 return b;
3232}
3233
3234static inline int div_roundup(int a, int b)
3235{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003236 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003237}
3238
3239static unsigned lcm(unsigned a, unsigned b)
3240{
3241 return (a * b) / gcd(a, b);
3242}
3243
3244struct stru1 {
3245 u8 freqs_reversed;
3246 u8 freq_diff_reduced;
3247 u8 freq_min_reduced;
3248 u8 divisor_f4_to_fmax;
3249 u8 divisor_f3_to_fmax;
3250 u8 freq4_to_max_remainder;
3251 u8 freq3_to_2_remainder;
3252 u8 freq3_to_2_remaindera;
3253 u8 freq4_to_2_remainder;
3254 int divisor_f3_to_f1, divisor_f4_to_f2;
3255 int common_time_unit_ps;
3256 int freq_max_reduced;
3257};
3258
3259static void
3260compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3261 int num_cycles_2, int num_cycles_1, int round_it,
3262 int add_freqs, struct stru1 *result)
3263{
3264 int g;
3265 int common_time_unit_ps;
3266 int freq1_reduced, freq2_reduced;
3267 int freq_min_reduced;
3268 int freq_max_reduced;
3269 int freq3, freq4;
3270
3271 g = gcd(freq1, freq2);
3272 freq1_reduced = freq1 / g;
3273 freq2_reduced = freq2 / g;
3274 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3275 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3276
3277 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3278 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3279 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3280 if (add_freqs) {
3281 freq3 += freq2_reduced;
3282 freq4 += freq1_reduced;
3283 }
3284
3285 if (round_it) {
3286 result->freq3_to_2_remainder = 0;
3287 result->freq3_to_2_remaindera = 0;
3288 result->freq4_to_max_remainder = 0;
3289 result->divisor_f4_to_f2 = 0;
3290 result->divisor_f3_to_f1 = 0;
3291 } else {
3292 if (freq2_reduced < freq1_reduced) {
3293 result->freq3_to_2_remainder =
3294 result->freq3_to_2_remaindera =
3295 freq3 % freq1_reduced - freq1_reduced + 1;
3296 result->freq4_to_max_remainder =
3297 -(freq4 % freq1_reduced);
3298 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3299 result->divisor_f4_to_f2 =
3300 (freq4 -
3301 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3302 result->freq4_to_2_remainder =
3303 -(char)((freq1_reduced - freq2_reduced) +
3304 ((u8) freq4 -
3305 (freq1_reduced -
3306 freq2_reduced)) % (u8) freq2_reduced);
3307 } else {
3308 if (freq2_reduced > freq1_reduced) {
3309 result->freq4_to_max_remainder =
3310 (freq4 % freq2_reduced) - freq2_reduced + 1;
3311 result->freq4_to_2_remainder =
3312 freq4 % freq_max_reduced -
3313 freq_max_reduced + 1;
3314 } else {
3315 result->freq4_to_max_remainder =
3316 -(freq4 % freq2_reduced);
3317 result->freq4_to_2_remainder =
3318 -(char)(freq4 % freq_max_reduced);
3319 }
3320 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3321 result->divisor_f3_to_f1 =
3322 (freq3 -
3323 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3324 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3325 result->freq3_to_2_remaindera =
3326 -(char)((freq_max_reduced - freq_min_reduced) +
3327 (freq3 -
3328 (freq_max_reduced -
3329 freq_min_reduced)) % freq1_reduced);
3330 }
3331 }
3332 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3333 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3334 if (round_it) {
3335 if (freq2_reduced > freq1_reduced) {
3336 if (freq3 % freq_max_reduced)
3337 result->divisor_f3_to_fmax++;
3338 }
3339 if (freq2_reduced < freq1_reduced) {
3340 if (freq4 % freq_max_reduced)
3341 result->divisor_f4_to_fmax++;
3342 }
3343 }
3344 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3345 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3346 result->freq_min_reduced = freq_min_reduced;
3347 result->common_time_unit_ps = common_time_unit_ps;
3348 result->freq_max_reduced = freq_max_reduced;
3349}
3350
3351static void
3352set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3353 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3354 int num_cycles_4, int reverse)
3355{
3356 struct stru1 vv;
3357 char multiplier;
3358
3359 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3360 0, 1, &vv);
3361
3362 multiplier =
3363 div_roundup(max
3364 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3365 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3366 div_roundup(num_cycles_1,
3367 vv.common_time_unit_ps) +
3368 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3369 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3370
3371 u32 y =
3372 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3373 vv.freq_max_reduced * multiplier)
3374 | (vv.
3375 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3376 multiplier) << 16) | ((u8) (vv.
3377 freq_min_reduced
3378 *
3379 multiplier)
3380 << 24);
3381 u32 x =
3382 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3383 divisor_f3_to_f1
3384 << 16)
3385 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3386 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003387 MCHBAR32(reg) = y;
3388 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003389 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003390 MCHBAR32(reg + 4) = y;
3391 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003392 }
3393}
3394
3395static void
3396set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3397 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3398 int num_cycles_4)
3399{
3400 struct stru1 ratios1;
3401 struct stru1 ratios2;
3402
3403 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3404 0, 1, &ratios2);
3405 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3406 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003407 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003408 ratios1.freq4_to_max_remainder | (ratios2.
3409 freq4_to_max_remainder
3410 << 8)
3411 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3412 divisor_f4_to_fmax
3413 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003414 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3415 (ratios2.freq4_to_max_remainder << 8) |
3416 (ratios1.divisor_f4_to_fmax << 16) |
3417 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003418}
3419
3420static void
3421set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3422 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3423{
3424 struct stru1 ratios;
3425
3426 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3427 round_it, add_freqs, &ratios);
3428 switch (mode) {
3429 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003430 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3431 (ratios.freqs_reversed << 8);
3432 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3433 (ratios.freq4_to_max_remainder << 8) |
3434 (ratios.divisor_f3_to_fmax << 16) |
3435 (ratios.divisor_f4_to_fmax << 20) |
3436 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003437 break;
3438
3439 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003440 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3441 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003442 break;
3443
3444 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003445 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3446 (ratios.freq4_to_max_remainder << 8) |
3447 (ratios.divisor_f3_to_fmax << 16) |
3448 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003449 break;
3450
3451 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003452 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3453 (ratios.divisor_f4_to_fmax << 8) |
3454 (ratios.freqs_reversed << 12) |
3455 (ratios.freq_min_reduced << 16) |
3456 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003457 break;
3458 }
3459}
3460
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003461static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003462{
3463 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3464 0, 1);
3465 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3466 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3467 1);
3468 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3469 frequency_11(info), 1231, 1524, 0, 1);
3470 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3471 frequency_11(info) / 2, 1278, 2008, 0, 1);
3472 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3473 1167, 1539, 0, 1);
3474 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3475 frequency_11(info) / 2, 1403, 1318, 0, 1);
3476 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3477 1);
3478 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3479 1);
3480 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3481 1, 1);
3482 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3483 1);
3484 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3485 frequency_11(info) / 2, 4000, 0, 0, 0);
3486 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3487 frequency_11(info) / 2, 4000, 4000, 0, 0);
3488
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003489 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003490 printk(RAM_SPEW, "[6dc] <= %x\n",
3491 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003492 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003493 } else
3494 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3495 info->delay46_ps[0], 0,
3496 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003497 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3498 frequency_11(info), 2500, 0, 0, 0);
3499 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3500 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003501 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003502 printk(RAM_SPEW, "[6e8] <= %x\n",
3503 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003504 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003505 } else
3506 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3507 info->delay46_ps[1], 0,
3508 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003509 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3510 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3511 470, 0);
3512 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3513 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3514 454, 459, 0);
3515 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3516 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3517 2588, 0);
3518 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3519 2405, 0);
3520 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3521 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3522 480, 0);
3523 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003524 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3525 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003526}
3527
3528static u16 get_max_timing(struct raminfo *info, int channel)
3529{
3530 int slot, rank, lane;
3531 u16 ret = 0;
3532
Felix Held04be2dd2018-07-29 04:53:22 +02003533 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003534 return 384;
3535
3536 if (info->revision < 8)
3537 return 256;
3538
3539 for (slot = 0; slot < NUM_SLOTS; slot++)
3540 for (rank = 0; rank < NUM_RANKS; rank++)
3541 if (info->populated_ranks[channel][slot][rank])
3542 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3543 ret = max(ret, read_500(info, channel,
3544 get_timing_register_addr
3545 (lane, 0, slot,
3546 rank), 9));
3547 return ret;
3548}
3549
3550static void set_274265(struct raminfo *info)
3551{
3552 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3553 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3554 int delay_e_over_cycle_ps;
3555 int cycletime_ps;
3556 int channel;
3557
3558 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003559 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003560 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3561 cycletime_ps =
3562 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3563 delay_d_ps =
3564 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3565 - info->some_delay_3_ps_rounded + 200;
3566 if (!
3567 ((info->silicon_revision == 0
3568 || info->silicon_revision == 1)
3569 && (info->revision >= 8)))
3570 delay_d_ps += halfcycle_ps(info) * 2;
3571 delay_d_ps +=
3572 halfcycle_ps(info) * (!info->revision_flag_1 +
3573 info->some_delay_2_halfcycles_ceil +
3574 2 * info->some_delay_1_cycle_floor +
3575 info->clock_speed_index +
3576 2 * info->cas_latency - 7 + 11);
3577 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3578
Felix Held04be2dd2018-07-29 04:53:22 +02003579 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3580 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3581 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003582 delay_d_ps += 650;
3583 delay_c_ps = delay_d_ps + 1800;
3584 if (delay_c_ps <= delay_a_ps)
3585 delay_e_ps = 0;
3586 else
3587 delay_e_ps =
3588 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3589 cycletime_ps);
3590
3591 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3592 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3593 delay_f_cycles =
3594 div_roundup(2500 - delay_e_over_cycle_ps,
3595 2 * halfcycle_ps(info));
3596 if (delay_f_cycles > delay_e_cycles) {
3597 info->delay46_ps[channel] = delay_e_ps;
3598 delay_e_cycles = 0;
3599 } else {
3600 info->delay46_ps[channel] =
3601 delay_e_over_cycle_ps +
3602 2 * halfcycle_ps(info) * delay_f_cycles;
3603 delay_e_cycles -= delay_f_cycles;
3604 }
3605
3606 if (info->delay46_ps[channel] < 2500) {
3607 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003608 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609 }
3610 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3611 if (delay_b_ps <= delay_a_ps)
3612 delay_b_ps = 0;
3613 else
3614 delay_b_ps -= delay_a_ps;
3615 info->delay54_ps[channel] =
3616 cycletime_ps * div_roundup(delay_b_ps,
3617 cycletime_ps) -
3618 2 * halfcycle_ps(info) * delay_e_cycles;
3619 if (info->delay54_ps[channel] < 2500)
3620 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003621 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3623 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003624 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003626 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003627 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3628 4 * halfcycle_ps(info)) - 6;
3629 MCHBAR32((channel << 10) + 0x274) =
3630 info->training.reg274265[channel][1] |
3631 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003632 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003633 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3634 4 * halfcycle_ps(info)) + 1;
3635 MCHBAR16((channel << 10) + 0x265) =
3636 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003638 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003639 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 else
Felix Held04be2dd2018-07-29 04:53:22 +02003641 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642}
3643
3644static void restore_274265(struct raminfo *info)
3645{
3646 int channel;
3647
3648 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003649 MCHBAR32((channel << 10) + 0x274) =
3650 (info->cached_training->reg274265[channel][0] << 16) |
3651 info->cached_training->reg274265[channel][1];
3652 MCHBAR16((channel << 10) + 0x265) =
3653 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003655 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003656 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657 else
Felix Held04be2dd2018-07-29 04:53:22 +02003658 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659}
3660
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661static void dmi_setup(void)
3662{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003663 gav(read8(DEFAULT_DMIBAR + 0x254));
3664 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3665 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003666 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003668 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669
3670 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3671 DEFAULT_GPIOBASE | 0x38);
3672 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3673}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003675void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003678 u16 ggc;
3679 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680
Felix Held04be2dd2018-07-29 04:53:22 +02003681 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3683 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003684 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003685 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686 }
Felix Held29a9c072018-07-29 01:34:45 +02003687#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003688 if (!s3resume) {
3689 pre_raminit_3(x2ca8);
3690 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003691 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003692#endif
3693
3694 dmi_setup();
3695
Felix Held04be2dd2018-07-29 04:53:22 +02003696 MCHBAR16(0x1170) = 0xa880;
3697 MCHBAR8(0x11c1) = 0x1;
3698 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003699 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003701 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3702 /* 0 for 32MB */
3703 gfxsize = 0;
3704 }
3705
3706 ggc = 0xb00 | ((gfxsize + 5) << 4);
3707
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003708 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003709
3710 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003711 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712
3713 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003714 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003715 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003716 MCHBAR16_OR(0x2c30, 0x200);
3717 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003718 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003719 pci_read_config8(GMA, 0x62); // = 0x2
3720 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003721 read8(DEFAULT_RCBA + 0x2318);
3722 write8(DEFAULT_RCBA + 0x2318, 0x47);
3723 read8(DEFAULT_RCBA + 0x2320);
3724 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725 }
3726
Felix Heldf83d80b2018-07-29 05:30:30 +02003727 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003729 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003730 gav(read32(DEFAULT_RCBA + 0x3428));
3731 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003732}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003733
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003734void raminit(const int s3resume, const u8 *spd_addrmap)
3735{
3736 unsigned channel, slot, lane, rank;
3737 int i;
3738 struct raminfo info;
3739 u8 x2ca8;
3740 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003741 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003742
Felix Heldf83d80b2018-07-29 05:30:30 +02003743 /* only used for dummy reads */
3744 volatile u8 tmp8;
3745 volatile u16 tmp16;
3746 volatile u32 tmp32;
3747
Felix Held04be2dd2018-07-29 04:53:22 +02003748 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003749 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003750
3751 memset(&info, 0x5a, sizeof(info));
3752
3753 info.last_500_command[0] = 0;
3754 info.last_500_command[1] = 0;
3755
3756 info.fsb_frequency = 135 * 2;
3757 info.board_lane_delay[0] = 0x14;
3758 info.board_lane_delay[1] = 0x07;
3759 info.board_lane_delay[2] = 0x07;
3760 info.board_lane_delay[3] = 0x08;
3761 info.board_lane_delay[4] = 0x56;
3762 info.board_lane_delay[5] = 0x04;
3763 info.board_lane_delay[6] = 0x04;
3764 info.board_lane_delay[7] = 0x05;
3765 info.board_lane_delay[8] = 0x10;
3766
3767 info.training.reg_178 = 0;
3768 info.training.reg_10b = 0;
3769
3770 info.heci_bar = 0;
3771 info.memory_reserved_for_heci_mb = 0;
3772
3773 /* before SPD */
3774 timestamp_add_now(101);
3775
Felix Held29a9c072018-07-29 01:34:45 +02003776 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003777 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003778
3779 collect_system_info(&info);
3780
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003781 /* Enable SMBUS. */
3782 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003783
3784 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3785
3786 info.use_ecc = 1;
3787 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003788 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003789 int v;
3790 int try;
3791 int addr;
3792 const u8 useful_addresses[] = {
3793 DEVICE_TYPE,
3794 MODULE_TYPE,
3795 DENSITY,
3796 RANKS_AND_DQ,
3797 MEMORY_BUS_WIDTH,
3798 TIMEBASE_DIVIDEND,
3799 TIMEBASE_DIVISOR,
3800 CYCLETIME,
3801 CAS_LATENCIES_LSB,
3802 CAS_LATENCIES_MSB,
3803 CAS_LATENCY_TIME,
3804 0x11, 0x12, 0x13, 0x14, 0x15,
3805 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3806 0x1c, 0x1d,
3807 THERMAL_AND_REFRESH,
3808 0x20,
3809 REFERENCE_RAW_CARD_USED,
3810 RANK1_ADDRESS_MAPPING,
3811 0x75, 0x76, 0x77, 0x78,
3812 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3813 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3814 0x85, 0x86, 0x87, 0x88,
3815 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3816 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3817 0x95
3818 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003819 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820 continue;
3821 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003822 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003823 DEVICE_TYPE);
3824 if (v >= 0)
3825 break;
3826 }
3827 if (v < 0)
3828 continue;
3829 for (addr = 0;
3830 addr <
3831 sizeof(useful_addresses) /
3832 sizeof(useful_addresses[0]); addr++)
3833 gav(info.
3834 spd[channel][0][useful_addresses
3835 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003836 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837 useful_addresses
3838 [addr]));
3839 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3840 die("Only DDR3 is supported");
3841
3842 v = info.spd[channel][0][RANKS_AND_DQ];
3843 info.populated_ranks[channel][0][0] = 1;
3844 info.populated_ranks[channel][0][1] =
3845 ((v >> 3) & 7);
3846 if (((v >> 3) & 7) > 1)
3847 die("At most 2 ranks are supported");
3848 if ((v & 7) == 0 || (v & 7) > 2)
3849 die("Only x8 and x16 modules are supported");
3850 if ((info.
3851 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3852 && (info.
3853 spd[channel][slot][MODULE_TYPE] & 0xF)
3854 != 3)
3855 die("Registered memory is not supported");
3856 info.is_x16_module[channel][0] = (v & 7) - 1;
3857 info.density[channel][slot] =
3858 info.spd[channel][slot][DENSITY] & 0xF;
3859 if (!
3860 (info.
3861 spd[channel][slot][MEMORY_BUS_WIDTH] &
3862 0x18))
3863 info.use_ecc = 0;
3864 }
3865
3866 gav(0x55);
3867
3868 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3869 int v = 0;
3870 for (slot = 0; slot < NUM_SLOTS; slot++)
3871 for (rank = 0; rank < NUM_RANKS; rank++)
3872 v |= info.
3873 populated_ranks[channel][slot][rank]
3874 << (2 * slot + rank);
3875 info.populated_ranks_mask[channel] = v;
3876 }
3877
3878 gav(0x55);
3879
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003880 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003881 }
3882
3883 /* after SPD */
3884 timestamp_add_now(102);
3885
Felix Held04be2dd2018-07-29 04:53:22 +02003886 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887
3888 collect_system_info(&info);
3889 calculate_timings(&info);
3890
Felix Held29a9c072018-07-29 01:34:45 +02003891#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003892 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893#endif
3894
3895 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003896 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003897 if (x2ca8 == 0 && (reg8 & 0x80)) {
3898 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3899 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3900 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3901 */
3902
3903 /* Clear bit7. */
3904
3905 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3906 (reg8 & ~(1 << 7)));
3907
3908 printk(BIOS_INFO,
3909 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003910 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911 }
3912 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913
3914 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003915 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3916 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003917
3918 compute_derived_timings(&info);
3919
3920 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003921 gav(MCHBAR8(0x164));
3922 MCHBAR8(0x164) = 0x26;
3923 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003924 }
3925
Felix Held04be2dd2018-07-29 04:53:22 +02003926 MCHBAR32_OR(0x18b4, 0x210000);
3927 MCHBAR32_OR(0x1890, 0x2000000);
3928 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003929
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003930 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3931 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003932
Felix Held04be2dd2018-07-29 04:53:22 +02003933 gav(MCHBAR16(0x2c10));
3934 MCHBAR16(0x2c10) = 0x412;
3935 gav(MCHBAR16(0x2c10));
3936 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003937
Felix Held04be2dd2018-07-29 04:53:22 +02003938 gav(MCHBAR8(0x2ca8)); // !!!!
3939 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003940
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003941 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3942 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003943 gav(MCHBAR32(0x1c04)); // !!!!
3944 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945
3946 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003947 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948 }
3949
Felix Held04be2dd2018-07-29 04:53:22 +02003950 MCHBAR32(0x18d8) = 0x120000;
3951 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003952 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3953 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003954 MCHBAR32(0x18d8) = 0x40000;
3955 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003956 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3957 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003958 MCHBAR32(0x18d8) = 0x180000;
3959 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003960 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3961 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003962 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003963
Felix Held04be2dd2018-07-29 04:53:22 +02003964 gav(MCHBAR32(0x18dc)); // !!!!
3965 MCHBAR32(0x18dc) = 0x3;
3966 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967
3968 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003969 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003970 }
3971
Felix Held04be2dd2018-07-29 04:53:22 +02003972 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003973 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003974 MCHBAR32(0x1a10) = 0x4200010e;
3975 MCHBAR32_OR(0x18b8, 0x200);
3976 gav(MCHBAR32(0x1918)); // !!!!
3977 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003978
Felix Held04be2dd2018-07-29 04:53:22 +02003979 gav(MCHBAR32(0x18b8)); // !!!!
3980 MCHBAR32(0x18b8) = 0xe00;
3981 gav(MCHBAR32(0x182c)); // !!!!
3982 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003983 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3984 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003985 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3986 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003987
Felix Held04be2dd2018-07-29 04:53:22 +02003988 MCHBAR32_AND(0x18b4, 0xffff7fff);
3989 gav(MCHBAR32(0x1a68)); // !!!!
3990 MCHBAR32(0x1a68) = 0x343800;
3991 gav(MCHBAR32(0x1e68)); // !!!!
3992 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003993
3994 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003995 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003996 }
3997
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003998 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3999 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
4000 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4001 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
4002 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4003 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4004 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02004005 gav(MCHBAR32(0x1af0)); // !!!!
4006 gav(MCHBAR32(0x1af0)); // !!!!
4007 MCHBAR32(0x1af0) = 0x1f020003;
4008 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004009
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004010 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004011 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004012 }
4013
Felix Held04be2dd2018-07-29 04:53:22 +02004014 gav(MCHBAR32(0x1890)); // !!!!
4015 MCHBAR32(0x1890) = 0x80102;
4016 gav(MCHBAR32(0x18b4)); // !!!!
4017 MCHBAR32(0x18b4) = 0x216000;
4018 MCHBAR32(0x18a4) = 0x22222222;
4019 MCHBAR32(0x18a8) = 0x22222222;
4020 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004021
4022 udelay(1000);
4023
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004024 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004025
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004026 if (x2ca8 == 0) {
4027 int j;
4028 if (s3resume && info.cached_training) {
4029 restore_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004030 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004031 info.cached_training->reg2ca9_bit0);
4032 for (i = 0; i < 2; i++)
4033 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004034 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004035 i, j, info.cached_training->reg274265[i][j]);
4036 } else {
4037 set_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004038 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004039 info.training.reg2ca9_bit0);
4040 for (i = 0; i < 2; i++)
4041 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004042 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004043 i, j, info.training.reg274265[i][j]);
4044 }
4045
4046 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004047
4048 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004049 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004050 }
4051
4052 udelay(1000);
4053
4054 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004055 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004056 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004057 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4058 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4059 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004060
Felix Heldf83d80b2018-07-29 05:30:30 +02004061 tmp8 = MCHBAR8(0x1150);
4062 tmp8 = MCHBAR8(0x1151);
4063 tmp8 = MCHBAR8(0x1022);
4064 tmp8 = MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004065 MCHBAR32(0x1300) = 0x60606060;
4066 MCHBAR32(0x1304) = 0x60606060;
4067 MCHBAR32(0x1308) = 0x78797a7b;
4068 MCHBAR32(0x130c) = 0x7c7d7e7f;
4069 MCHBAR32(0x1310) = 0x60606060;
4070 MCHBAR32(0x1314) = 0x60606060;
4071 MCHBAR32(0x1318) = 0x60606060;
4072 MCHBAR32(0x131c) = 0x60606060;
4073 MCHBAR32(0x1320) = 0x50515253;
4074 MCHBAR32(0x1324) = 0x54555657;
4075 MCHBAR32(0x1328) = 0x58595a5b;
4076 MCHBAR32(0x132c) = 0x5c5d5e5f;
4077 MCHBAR32(0x1330) = 0x40414243;
4078 MCHBAR32(0x1334) = 0x44454647;
4079 MCHBAR32(0x1338) = 0x48494a4b;
4080 MCHBAR32(0x133c) = 0x4c4d4e4f;
4081 MCHBAR32(0x1340) = 0x30313233;
4082 MCHBAR32(0x1344) = 0x34353637;
4083 MCHBAR32(0x1348) = 0x38393a3b;
4084 MCHBAR32(0x134c) = 0x3c3d3e3f;
4085 MCHBAR32(0x1350) = 0x20212223;
4086 MCHBAR32(0x1354) = 0x24252627;
4087 MCHBAR32(0x1358) = 0x28292a2b;
4088 MCHBAR32(0x135c) = 0x2c2d2e2f;
4089 MCHBAR32(0x1360) = 0x10111213;
4090 MCHBAR32(0x1364) = 0x14151617;
4091 MCHBAR32(0x1368) = 0x18191a1b;
4092 MCHBAR32(0x136c) = 0x1c1d1e1f;
4093 MCHBAR32(0x1370) = 0x10203;
4094 MCHBAR32(0x1374) = 0x4050607;
4095 MCHBAR32(0x1378) = 0x8090a0b;
4096 MCHBAR32(0x137c) = 0xc0d0e0f;
4097 MCHBAR8(0x11cc) = 0x4e;
4098 MCHBAR32(0x1110) = 0x73970404;
4099 MCHBAR32(0x1114) = 0x72960404;
4100 MCHBAR32(0x1118) = 0x6f950404;
4101 MCHBAR32(0x111c) = 0x6d940404;
4102 MCHBAR32(0x1120) = 0x6a930404;
4103 MCHBAR32(0x1124) = 0x68a41404;
4104 MCHBAR32(0x1128) = 0x66a21404;
4105 MCHBAR32(0x112c) = 0x63a01404;
4106 MCHBAR32(0x1130) = 0x609e1404;
4107 MCHBAR32(0x1134) = 0x5f9c1404;
4108 MCHBAR32(0x1138) = 0x5c961404;
4109 MCHBAR32(0x113c) = 0x58a02404;
4110 MCHBAR32(0x1140) = 0x54942404;
4111 MCHBAR32(0x1190) = 0x900080a;
4112 MCHBAR16(0x11c0) = 0xc40b;
4113 MCHBAR16(0x11c2) = 0x303;
4114 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004115 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004116 MCHBAR32(0x11b8) = 0x70c3000;
4117 MCHBAR8(0x11ec) = 0xa;
4118 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004119 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004120 MCHBAR16(0x11ca) = 0xfa;
4121 MCHBAR32(0x11e4) = 0x4e20;
4122 MCHBAR8(0x11bc) = 0xf;
4123 MCHBAR16(0x11da) = 0x19;
4124 MCHBAR16(0x11ba) = 0x470c;
4125 MCHBAR32(0x1680) = 0xe6ffe4ff;
4126 MCHBAR32(0x1684) = 0xdeffdaff;
4127 MCHBAR32(0x1688) = 0xd4ffd0ff;
4128 MCHBAR32(0x168c) = 0xccffc6ff;
4129 MCHBAR32(0x1690) = 0xc0ffbeff;
4130 MCHBAR32(0x1694) = 0xb8ffb0ff;
4131 MCHBAR32(0x1698) = 0xa8ff0000;
4132 MCHBAR32(0x169c) = 0xc00;
4133 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004134 }
4135
Felix Held04be2dd2018-07-29 04:53:22 +02004136 MCHBAR32(0x124c) = 0x15040d00;
4137 MCHBAR32(0x1250) = 0x7f0000;
4138 MCHBAR32(0x1254) = 0x1e220004;
4139 MCHBAR32(0x1258) = 0x4000004;
4140 MCHBAR32(0x1278) = 0x0;
4141 MCHBAR32(0x125c) = 0x0;
4142 MCHBAR32(0x1260) = 0x0;
4143 MCHBAR32(0x1264) = 0x0;
4144 MCHBAR32(0x1268) = 0x0;
4145 MCHBAR32(0x126c) = 0x0;
4146 MCHBAR32(0x1270) = 0x0;
4147 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004148 }
4149
4150 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004151 MCHBAR16(0x1214) = 0x320;
4152 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004153 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4154 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004155 MCHBAR32(0x1400) = 0x13040020;
4156 MCHBAR32(0x1404) = 0xe090120;
4157 MCHBAR32(0x1408) = 0x5120220;
4158 MCHBAR32(0x140c) = 0x5120330;
4159 MCHBAR32(0x1410) = 0xe090220;
4160 MCHBAR32(0x1414) = 0x1010001;
4161 MCHBAR32(0x1418) = 0x1110000;
4162 MCHBAR32(0x141c) = 0x9020020;
4163 MCHBAR32(0x1420) = 0xd090220;
4164 MCHBAR32(0x1424) = 0x2090220;
4165 MCHBAR32(0x1428) = 0x2090330;
4166 MCHBAR32(0x142c) = 0xd090220;
4167 MCHBAR32(0x1430) = 0x1010001;
4168 MCHBAR32(0x1434) = 0x1110000;
4169 MCHBAR32(0x1438) = 0x11040020;
4170 MCHBAR32(0x143c) = 0x4030220;
4171 MCHBAR32(0x1440) = 0x1060220;
4172 MCHBAR32(0x1444) = 0x1060330;
4173 MCHBAR32(0x1448) = 0x4030220;
4174 MCHBAR32(0x144c) = 0x1010001;
4175 MCHBAR32(0x1450) = 0x1110000;
4176 MCHBAR32(0x1454) = 0x4010020;
4177 MCHBAR32(0x1458) = 0xb090220;
4178 MCHBAR32(0x145c) = 0x1090220;
4179 MCHBAR32(0x1460) = 0x1090330;
4180 MCHBAR32(0x1464) = 0xb090220;
4181 MCHBAR32(0x1468) = 0x1010001;
4182 MCHBAR32(0x146c) = 0x1110000;
4183 MCHBAR32(0x1470) = 0xf040020;
4184 MCHBAR32(0x1474) = 0xa090220;
4185 MCHBAR32(0x1478) = 0x1120220;
4186 MCHBAR32(0x147c) = 0x1120330;
4187 MCHBAR32(0x1480) = 0xa090220;
4188 MCHBAR32(0x1484) = 0x1010001;
4189 MCHBAR32(0x1488) = 0x1110000;
4190 MCHBAR32(0x148c) = 0x7020020;
4191 MCHBAR32(0x1490) = 0x1010220;
4192 MCHBAR32(0x1494) = 0x10210;
4193 MCHBAR32(0x1498) = 0x10320;
4194 MCHBAR32(0x149c) = 0x1010220;
4195 MCHBAR32(0x14a0) = 0x1010001;
4196 MCHBAR32(0x14a4) = 0x1110000;
4197 MCHBAR32(0x14a8) = 0xd040020;
4198 MCHBAR32(0x14ac) = 0x8090220;
4199 MCHBAR32(0x14b0) = 0x1111310;
4200 MCHBAR32(0x14b4) = 0x1111420;
4201 MCHBAR32(0x14b8) = 0x8090220;
4202 MCHBAR32(0x14bc) = 0x1010001;
4203 MCHBAR32(0x14c0) = 0x1110000;
4204 MCHBAR32(0x14c4) = 0x3010020;
4205 MCHBAR32(0x14c8) = 0x7090220;
4206 MCHBAR32(0x14cc) = 0x1081310;
4207 MCHBAR32(0x14d0) = 0x1081420;
4208 MCHBAR32(0x14d4) = 0x7090220;
4209 MCHBAR32(0x14d8) = 0x1010001;
4210 MCHBAR32(0x14dc) = 0x1110000;
4211 MCHBAR32(0x14e0) = 0xb040020;
4212 MCHBAR32(0x14e4) = 0x2030220;
4213 MCHBAR32(0x14e8) = 0x1051310;
4214 MCHBAR32(0x14ec) = 0x1051420;
4215 MCHBAR32(0x14f0) = 0x2030220;
4216 MCHBAR32(0x14f4) = 0x1010001;
4217 MCHBAR32(0x14f8) = 0x1110000;
4218 MCHBAR32(0x14fc) = 0x5020020;
4219 MCHBAR32(0x1500) = 0x5090220;
4220 MCHBAR32(0x1504) = 0x2071310;
4221 MCHBAR32(0x1508) = 0x2071420;
4222 MCHBAR32(0x150c) = 0x5090220;
4223 MCHBAR32(0x1510) = 0x1010001;
4224 MCHBAR32(0x1514) = 0x1110000;
4225 MCHBAR32(0x1518) = 0x7040120;
4226 MCHBAR32(0x151c) = 0x2090220;
4227 MCHBAR32(0x1520) = 0x70b1210;
4228 MCHBAR32(0x1524) = 0x70b1310;
4229 MCHBAR32(0x1528) = 0x2090220;
4230 MCHBAR32(0x152c) = 0x1010001;
4231 MCHBAR32(0x1530) = 0x1110000;
4232 MCHBAR32(0x1534) = 0x1010110;
4233 MCHBAR32(0x1538) = 0x1081310;
4234 MCHBAR32(0x153c) = 0x5041200;
4235 MCHBAR32(0x1540) = 0x5041310;
4236 MCHBAR32(0x1544) = 0x1081310;
4237 MCHBAR32(0x1548) = 0x1010001;
4238 MCHBAR32(0x154c) = 0x1110000;
4239 MCHBAR32(0x1550) = 0x1040120;
4240 MCHBAR32(0x1554) = 0x4051210;
4241 MCHBAR32(0x1558) = 0xd051200;
4242 MCHBAR32(0x155c) = 0xd051200;
4243 MCHBAR32(0x1560) = 0x4051210;
4244 MCHBAR32(0x1564) = 0x1010001;
4245 MCHBAR32(0x1568) = 0x1110000;
4246 MCHBAR16(0x1222) = 0x220a;
4247 MCHBAR16(0x123c) = 0x1fc0;
4248 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004249 }
4250
Felix Heldf83d80b2018-07-29 05:30:30 +02004251 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
4252 tmp32 = MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254
Felix Heldf83d80b2018-07-29 05:30:30 +02004255 tmp8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004256
4257 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR8_AND(0x2ca8, ~3);
4259 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4260 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004261 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004262 }
4263
Felix Held04be2dd2018-07-29 04:53:22 +02004264 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004265 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004266 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Felix Heldf83d80b2018-07-29 05:30:30 +02004267 tmp16 = MCHBAR16(0x2c20); // !!!!
4268 tmp16 = MCHBAR16(0x2c10); // !!!!
4269 tmp16 = MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004271 udelay(1000);
4272 write_1d0(0, 0x33d, 0, 0);
4273 write_500(&info, 0, 0, 0xb61, 0, 0);
4274 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004275 MCHBAR32(0x1a30) = 0x0;
4276 MCHBAR32(0x1a34) = 0x0;
4277 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4278 (info.populated_ranks[0][0][0] * 0xa0);
4279 MCHBAR16(0x616) = 0x26a;
4280 MCHBAR32(0x134) = 0x856000;
4281 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004282 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4283 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004284 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004285 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4286 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004287 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004288 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004289 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4290 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004291 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4292 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4293 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4294 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4295 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4296 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4297 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4298 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4299 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4300 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004301 }
4302
4303 write_1d0(0x4, 0x151, 4, 1);
4304 write_1d0(0, 0x142, 3, 1);
4305 rdmsr(0x1ac); // !!!!
4306 write_500(&info, 1, 1, 0x6b3, 4, 1);
4307 write_500(&info, 1, 1, 0x6cf, 4, 1);
4308
4309 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4310
4311 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4312 populated_ranks[0]
4313 [0][0]) << 0),
4314 0x1d1, 3, 1);
4315 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004316 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4317 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004318 }
4319
4320 set_334(0);
4321
4322 program_base_timings(&info);
4323
Felix Held04be2dd2018-07-29 04:53:22 +02004324 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004325
4326 write_1d0(0x2, 0x1d5, 2, 1);
4327 write_1d0(0x20, 0x166, 7, 1);
4328 write_1d0(0x0, 0xeb, 3, 1);
4329 write_1d0(0x0, 0xf3, 6, 1);
4330
4331 for (channel = 0; channel < NUM_CHANNELS; channel++)
4332 for (lane = 0; lane < 9; lane++) {
4333 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4334 u8 a;
4335 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4336 write_500(&info, channel, a, addr, 6, 1);
4337 }
4338
4339 udelay(1000);
4340
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004341 if (s3resume) {
4342 if (info.cached_training == NULL) {
4343 u32 reg32;
4344 printk(BIOS_ERR,
4345 "Couldn't find training data. Rebooting\n");
4346 reg32 = inl(DEFAULT_PMBASE + 0x04);
4347 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004348 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004349 }
4350 int tm;
4351 info.training = *info.cached_training;
4352 for (tm = 0; tm < 4; tm++)
4353 for (channel = 0; channel < NUM_CHANNELS; channel++)
4354 for (slot = 0; slot < NUM_SLOTS; slot++)
4355 for (rank = 0; rank < NUM_RANKS; rank++)
4356 for (lane = 0; lane < 9; lane++)
4357 write_500(&info,
4358 channel,
4359 info.training.
4360 lane_timings
4361 [tm][channel]
4362 [slot][rank]
4363 [lane],
4364 get_timing_register_addr
4365 (lane, tm,
4366 slot, rank),
4367 9, 0);
4368 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4369 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4370 }
4371
Felix Heldf83d80b2018-07-29 05:30:30 +02004372 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004373 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004374 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
4375 tmp8 = MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004376
4377 program_board_delay(&info);
4378
Felix Held04be2dd2018-07-29 04:53:22 +02004379 MCHBAR8(0x5ff) = 0x0;
4380 MCHBAR8(0x5ff) = 0x80;
4381 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004382
Felix Held04be2dd2018-07-29 04:53:22 +02004383 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004384 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004385 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004386 gav(read_1d0(0x14b, 7)); // = 0x81023100
4387 write_1d0(0x30, 0x14b, 7, 1);
4388 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4389 write_1d0(7, 0xd6, 6, 1);
4390 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4391 write_1d0(7, 0x328, 6, 1);
4392
4393 for (channel = 0; channel < NUM_CHANNELS; channel++)
4394 set_4cf(&info, channel,
4395 info.populated_ranks[channel][0][0] ? 8 : 0);
4396
4397 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4398 write_1d0(2, 0x116, 4, 1);
4399 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4400 write_1d0(0, 0xae, 6, 1);
4401 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4402 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004403 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4404 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004405 MCHBAR32_AND(0x140, ~0x07000000);
4406 MCHBAR32_AND(0x138, ~0x07000000);
4407 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004408 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004409 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004410 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004411
4412 {
4413 u32 t;
4414 u8 val_a1;
4415 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4416 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4417 rmw_1d0(0x320, 0x07,
4418 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4419 rmw_1d0(0x14b, 0x78,
4420 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4421 4), 7,
4422 1);
4423 rmw_1d0(0xce, 0x38,
4424 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4425 4), 6,
4426 1);
4427 }
4428
4429 for (channel = 0; channel < NUM_CHANNELS; channel++)
4430 set_4cf(&info, channel,
4431 info.populated_ranks[channel][0][0] ? 9 : 1);
4432
4433 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Felix Heldf83d80b2018-07-29 05:30:30 +02004434 tmp32 = MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004435 write_1d0(2, 0xae, 6, 1);
4436 write_1d0(2, 0x300, 6, 1);
4437 write_1d0(2, 0x121, 3, 1);
4438 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4439 write_1d0(4, 0xd6, 6, 1);
4440 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4441 write_1d0(4, 0x328, 6, 1);
4442
4443 for (channel = 0; channel < NUM_CHANNELS; channel++)
4444 set_4cf(&info, channel,
4445 info.populated_ranks[channel][0][0] ? 9 : 0);
4446
Felix Held04be2dd2018-07-29 04:53:22 +02004447 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4448 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004449 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004450 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004451 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4452 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4453 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4454 write_1d0(0, 0x21c, 6, 1);
4455 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4456 write_1d0(0x35, 0x14b, 7, 1);
4457
4458 for (channel = 0; channel < NUM_CHANNELS; channel++)
4459 set_4cf(&info, channel,
4460 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4461
4462 set_334(1);
4463
Felix Held04be2dd2018-07-29 04:53:22 +02004464 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004465
4466 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4467 write_500(&info, channel,
4468 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4469 1);
4470 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4471 }
Felix Held04be2dd2018-07-29 04:53:22 +02004472 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4473 MCHBAR16(0x6c0) = 0x14a0;
4474 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4475 MCHBAR16(0x232) = 0x8;
4476 /* 0x40004 or 0 depending on ? */
4477 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4478 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4479 MCHBAR32(0x128) = 0x2150d05;
4480 MCHBAR8(0x12c) = 0x1f;
4481 MCHBAR8(0x12d) = 0x56;
4482 MCHBAR8(0x12e) = 0x31;
4483 MCHBAR8(0x12f) = 0x0;
4484 MCHBAR8(0x271) = 0x2;
4485 MCHBAR8(0x671) = 0x2;
4486 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004487 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004488 MCHBAR32(0x294 + (channel << 10)) =
4489 (info.populated_ranks_mask[channel] & 3) << 16;
4490 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4491 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004493 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4494 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495
4496 if (!s3resume)
4497 jedec_init(&info);
4498
4499 int totalrank = 0;
4500 for (channel = 0; channel < NUM_CHANNELS; channel++)
4501 for (slot = 0; slot < NUM_SLOTS; slot++)
4502 for (rank = 0; rank < NUM_RANKS; rank++)
4503 if (info.populated_ranks[channel][slot][rank]) {
4504 jedec_read(&info, channel, slot, rank,
4505 totalrank, 0xa, 0x400);
4506 totalrank++;
4507 }
4508
Felix Held04be2dd2018-07-29 04:53:22 +02004509 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510
Felix Heldf83d80b2018-07-29 05:30:30 +02004511 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4512 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513
4514 if (!s3resume) {
4515 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004516 MCHBAR32(0x294 + (channel << 10)) =
4517 (info.populated_ranks_mask[channel] & 3) << 16;
4518 MCHBAR16(0x298 + (channel << 10)) =
4519 info.populated_ranks[channel][0][0] |
4520 (info.populated_ranks[channel][0][1] << 5);
4521 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004523 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524
4525 {
4526 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004527 a = MCHBAR8(0x243);
4528 b = MCHBAR8(0x643);
4529 MCHBAR8(0x243) = a | 2;
4530 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 }
4532
4533 write_1d0(7, 0x19b, 3, 1);
4534 write_1d0(7, 0x1c0, 3, 1);
4535 write_1d0(4, 0x1c6, 4, 1);
4536 write_1d0(4, 0x1cc, 4, 1);
4537 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4538 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004539 MCHBAR32(0x584) = 0xfffff;
4540 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541
4542 for (channel = 0; channel < NUM_CHANNELS; channel++)
4543 for (slot = 0; slot < NUM_SLOTS; slot++)
4544 for (rank = 0; rank < NUM_RANKS; rank++)
4545 if (info.
4546 populated_ranks[channel][slot]
4547 [rank])
4548 config_rank(&info, s3resume,
4549 channel, slot,
4550 rank);
4551
Felix Held04be2dd2018-07-29 04:53:22 +02004552 MCHBAR8(0x243) = 0x1;
4553 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554 }
4555
4556 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004557 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 write_26c(0, 0x820);
4559 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004560 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561 /* end */
4562
4563 if (s3resume) {
4564 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004565 MCHBAR32(0x294 + (channel << 10)) =
4566 (info.populated_ranks_mask[channel] & 3) << 16;
4567 MCHBAR16(0x298 + (channel << 10)) =
4568 info.populated_ranks[channel][0][0] |
4569 (info.populated_ranks[channel][0][1] << 5);
4570 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004572 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573 }
4574
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR32_AND(0xfa4, ~0x01000002);
4576 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 /* Before training. */
4579 timestamp_add_now(103);
4580
4581 if (!s3resume)
4582 ram_training(&info);
4583
4584 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004585 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586
4587 dump_timings(&info);
4588
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 program_modules_memory_map(&info, 0);
4590 program_total_memory_map(&info);
4591
4592 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004593 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004597 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598 else
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600
Felix Held04be2dd2018-07-29 04:53:22 +02004601 MCHBAR32_AND(0xfac, ~0x80000000);
4602 MCHBAR32(0xfb4) = 0x4800;
4603 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4604 MCHBAR32(0xe94) = 0x7ffff;
4605 MCHBAR32(0xfc0) = 0x80002040;
4606 MCHBAR32(0xfc4) = 0x701246;
4607 MCHBAR8_AND(0xfc8, ~0x70);
4608 MCHBAR32_OR(0xe5c, 0x1000000);
4609 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4610 MCHBAR32(0x50) = 0x700b0;
4611 MCHBAR32(0x3c) = 0x10;
4612 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4613 MCHBAR8_OR(0xff4, 0x2);
4614 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004615
Felix Held29a9c072018-07-29 01:34:45 +02004616#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004617 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4618 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4619 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004620
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004621 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4622 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4623 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624
4625#else
4626 {
4627 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004628 // = 0xe911714b
4629 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4630 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4631 // = 0xe911714b
4632 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4633 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634 }
4635#endif
4636
4637 {
4638 u32 eax;
4639
4640 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4642 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4643 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644 }
4645
4646 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004649 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004650 else
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652
Felix Held04be2dd2018-07-29 04:53:22 +02004653 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
Felix Held04be2dd2018-07-29 04:53:22 +02004655 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004656 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658 else
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
4664 {
4665 u8 al;
4666 al = 0xd;
4667 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4668 al += 2;
4669 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004670 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004671 }
4672
4673 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4675 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4676 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4677 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678 }
4679 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004680 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004681 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004682 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004683 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Felix Heldf83d80b2018-07-29 05:30:30 +02004684 tmp8 = MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004685 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR8_OR(0x1210, 2);
4687 MCHBAR32(0x1200) = 0x8800440;
4688 MCHBAR32(0x1204) = 0x53ff0453;
4689 MCHBAR32(0x1208) = 0x19002043;
4690 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
4692 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR16(0x1214) = 0x220;
4694 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 }
4696
Felix Held04be2dd2018-07-29 04:53:22 +02004697 MCHBAR8_OR(0x1214, 0x4);
4698 MCHBAR8(0x120c) = 0x1;
4699 MCHBAR8(0x1218) = 0x3;
4700 MCHBAR8(0x121a) = 0x3;
4701 MCHBAR8(0x121c) = 0x3;
4702 MCHBAR16(0xc14) = 0x0;
4703 MCHBAR16(0xc20) = 0x0;
4704 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705
4706 /* revision dependent here. */
4707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709
4710 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712
Felix Held04be2dd2018-07-29 04:53:22 +02004713 MCHBAR16_OR(0x1230, 0x8000);
4714 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004715
4716 u8 bl, ebpb;
4717 u16 reg_1020;
4718
Felix Held04be2dd2018-07-29 04:53:22 +02004719 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4720 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR32(0x1000) = 0x100;
4723 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724
4725 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004726 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727 bl = reg_1020 >> 8;
4728 ebpb = reg_1020 & 0xff;
4729 } else {
4730 ebpb = 0;
4731 bl = 8;
4732 }
4733
4734 rdmsr(0x1a2);
4735
Felix Held04be2dd2018-07-29 04:53:22 +02004736 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004737
Felix Held04be2dd2018-07-29 04:53:22 +02004738 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004739
Felix Held04be2dd2018-07-29 04:53:22 +02004740 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004741
Felix Held04be2dd2018-07-29 04:53:22 +02004742 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004744 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4745 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004746 }
4747
4748 setup_heci_uma(&info);
4749
4750 if (info.uma_enabled) {
4751 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004752 MCHBAR32_OR(0x11b0, 0x4000);
4753 MCHBAR32_OR(0x11b4, 0x4000);
4754 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755
Felix Held04be2dd2018-07-29 04:53:22 +02004756 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4757 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4758 MCHBAR16_OR(0x1170, 0x1000);
4759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004761
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004762 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004763 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004764 ;
4765 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004766 }
4767
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004768 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4769 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004770 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004771 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004772
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004773 udelay(1000);
4774 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004775 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4776
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004777 if (!s3resume)
4778 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004779 if (s3resume && cbmem_wasnot_inited) {
4780 u32 reg32;
4781 printk(BIOS_ERR, "Failed S3 resume.\n");
4782 ram_check(0x100000, 0x200000);
4783
4784 /* Clear SLP_TYPE. */
4785 reg32 = inl(DEFAULT_PMBASE + 0x04);
4786 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4787
4788 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004789 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004790 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004791}