blob: 686089fdd08240c938e33fe43d3563a2acf11506 [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
28#include <pc80/mc146818rtc.h>
29#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020040#include <types.h>
41
42#include "chip.h"
43#include "nehalem.h"
44#include "raminit.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010045
46#define NORTHBRIDGE PCI_DEV(0, 0, 0)
47#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
48#define GMA PCI_DEV (0, 0x2, 0x0)
49#define HECIDEV PCI_DEV(0, 0x16, 0)
50#define HECIBAR 0x10
51
52#define FOR_ALL_RANKS \
53 for (channel = 0; channel < NUM_CHANNELS; channel++) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++)
56
57#define FOR_POPULATED_RANKS \
58 for (channel = 0; channel < NUM_CHANNELS; channel++) \
59 for (slot = 0; slot < NUM_SLOTS; slot++) \
60 for (rank = 0; rank < NUM_RANKS; rank++) \
61 if (info->populated_ranks[channel][slot][rank])
62
63#define FOR_POPULATED_RANKS_BACKWARDS \
64 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
65 for (slot = 0; slot < NUM_SLOTS; slot++) \
66 for (rank = 0; rank < NUM_RANKS; rank++) \
67 if (info->populated_ranks[channel][slot][rank])
68
69/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
70typedef struct {
71 u8 smallest;
72 u8 largest;
73} timing_bounds_t[2][2][2][9];
74
Arthur Heymansdc71e252018-01-29 10:14:48 +010075#define MRC_CACHE_VERSION 1
76
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010077struct ram_training {
78 /* [TM][CHANNEL][SLOT][RANK][LANE] */
79 u16 lane_timings[4][2][2][2][9];
80 u16 reg_178;
81 u16 reg_10b;
82
83 u8 reg178_center;
84 u8 reg178_smallest;
85 u8 reg178_largest;
86 timing_bounds_t timing_bounds[2];
87 u16 timing_offset[2][2][2][9];
88 u16 timing2_offset[2][2][2][9];
89 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010090 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
91 u8 reg2ca9_bit0;
92 u32 reg_6dc;
93 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094};
95
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096#include <lib.h> /* Prototypes */
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010099static void clflush(u32 addr)
100{
101 asm volatile ("clflush (%0)"::"r" (addr));
102}
103
104typedef struct _u128 {
105 u64 lo;
106 u64 hi;
107} u128;
108
109static void read128(u32 addr, u64 * out)
110{
111 u128 ret;
112 u128 stor;
113 asm volatile ("movdqu %%xmm0, %0\n"
114 "movdqa (%2), %%xmm0\n"
115 "movdqu %%xmm0, %1\n"
116 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
117 out[0] = ret.lo;
118 out[1] = ret.hi;
119}
120
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100121/* OK */
122static void write_1d0(u32 val, u16 addr, int bits, int flag)
123{
Felix Held04be2dd2018-07-29 04:53:22 +0200124 MCHBAR32(0x1d0) = 0;
125 while (MCHBAR32(0x1d0) & 0x800000)
126 ;
127 MCHBAR32(0x1d4) =
128 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
129 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200130 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200131 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100132}
133
134/* OK */
135static u16 read_1d0(u16 addr, int split)
136{
137 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200138 MCHBAR32(0x1d0) = 0;
139 while (MCHBAR32(0x1d0) & 0x800000)
140 ;
141 MCHBAR32(0x1d0) =
142 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
143 while (MCHBAR32(0x1d0) & 0x800000)
144 ;
145 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146 write_1d0(0, 0x33d, 0, 0);
147 write_1d0(0, 0x33d, 0, 0);
148 val &= ((1 << split) - 1);
149 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
150 return val;
151}
152
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800153static void write32p(uintptr_t addr, uint32_t val)
154{
155 write32((void *)addr, val);
156}
157
158static uint32_t read32p(uintptr_t addr)
159{
160 return read32((void *)addr);
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static void sfence(void)
164{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100165 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100166}
167
168static inline u16 get_lane_offset(int slot, int rank, int lane)
169{
170 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
171 0x452 * (lane == 8);
172}
173
174static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
175{
176 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
177 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
178}
179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180static u32 gav_real(int line, u32 in)
181{
182 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
183 return in;
184}
185
186#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200187
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100188struct raminfo {
189 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
190 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
191 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
192 u8 density[2][2]; /* [CHANNEL][SLOT] */
193 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
194 int rank_start[2][2][2];
195 u8 cas_latency;
196 u8 board_lane_delay[9];
197 u8 use_ecc;
198 u8 revision;
199 u8 max_supported_clock_speed_index;
200 u8 uma_enabled;
201 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
202 u8 silicon_revision;
203 u8 populated_ranks_mask[2];
204 u8 max_slots_used_in_channel;
205 u8 mode4030[2];
206 u16 avg4044[2];
207 u16 max4048[2];
208 unsigned total_memory_mb;
209 unsigned interleaved_part_mb;
210 unsigned non_interleaved_part_mb;
211
212 u32 heci_bar;
213 u64 heci_uma_addr;
214 unsigned memory_reserved_for_heci_mb;
215
216 struct ram_training training;
217 u32 last_500_command[2];
218
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100219 u32 delay46_ps[2];
220 u32 delay54_ps[2];
221 u8 revision_flag_1;
222 u8 some_delay_1_cycle_floor;
223 u8 some_delay_2_halfcycles_ceil;
224 u8 some_delay_3_ps_rounded;
225
226 const struct ram_training *cached_training;
227};
228
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200229/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100230timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200231
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232static void
233write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
234 int flag);
235
236/* OK */
237static u16
238read_500(struct raminfo *info, int channel, u16 addr, int split)
239{
240 u32 val;
241 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200242 MCHBAR32(0x500 + (channel << 10)) = 0;
243 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
244 ;
245 MCHBAR32(0x500 + (channel << 10)) =
246 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
247 + 0xb88 - addr);
248 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
249 ;
250 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100251 return val & ((1 << split) - 1);
252}
253
254/* OK */
255static void
256write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
257 int flag)
258{
259 if (info->last_500_command[channel] == 0x80000000) {
260 info->last_500_command[channel] = 0x40000000;
261 write_500(info, channel, 0, 0xb61, 0, 0);
262 }
Felix Held04be2dd2018-07-29 04:53:22 +0200263 MCHBAR32(0x500 + (channel << 10)) = 0;
264 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
265 ;
266 MCHBAR32(0x504 + (channel << 10)) =
267 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
268 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200269 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200270 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100271}
272
273static int rw_test(int rank)
274{
275 const u32 mask = 0xf00fc33c;
276 int ok = 0xff;
277 int i;
278 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 sfence();
281 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100283 sfence();
284 for (i = 0; i < 32; i++) {
285 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800286 write32p((rank << 28) | (i << 3), pat);
287 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288 }
289 sfence();
290 for (i = 0; i < 32; i++) {
291 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
292 int j;
293 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100299 for (j = 0; j < 4; j++)
300 if (((val >> (j * 8)) & 0xff) != pat)
301 ok &= ~(16 << j);
302 }
303 sfence();
304 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800305 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100306 sfence();
307 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800308 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100309
310 return ok;
311}
312
313static void
314program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
315{
316 int lane;
317 for (lane = 0; lane < 8; lane++) {
318 write_500(info, channel,
319 base +
320 info->training.
321 lane_timings[2][channel][slot][rank][lane],
322 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
323 write_500(info, channel,
324 base +
325 info->training.
326 lane_timings[3][channel][slot][rank][lane],
327 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
328 }
329}
330
331static void write_26c(int channel, u16 si)
332{
Felix Held04be2dd2018-07-29 04:53:22 +0200333 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
334 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
335 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100336}
337
338static u32 get_580(int channel, u8 addr)
339{
340 u32 ret;
341 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200342 MCHBAR8(0x5ff) = 0x0;
343 MCHBAR8(0x5ff) = 0x80;
344 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
345 MCHBAR8_OR(0x580 + (channel << 10), 1);
346 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
347 ;
348 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100349 return ret;
350}
351
352const int cached_config = 0;
353
354#define NUM_CHANNELS 2
355#define NUM_SLOTS 2
356#define NUM_RANKS 2
357#define RANK_SHIFT 28
358#define CHANNEL_SHIFT 10
359
360#include "raminit_tables.c"
361
362static void seq9(struct raminfo *info, int channel, int slot, int rank)
363{
364 int i, lane;
365
366 for (i = 0; i < 2; i++)
367 for (lane = 0; lane < 8; lane++)
368 write_500(info, channel,
369 info->training.lane_timings[i +
370 1][channel][slot]
371 [rank][lane], get_timing_register_addr(lane,
372 i + 1,
373 slot,
374 rank),
375 9, 0);
376
377 write_1d0(1, 0x103, 6, 1);
378 for (lane = 0; lane < 8; lane++)
379 write_500(info, channel,
380 info->training.
381 lane_timings[0][channel][slot][rank][lane],
382 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
383
384 for (i = 0; i < 2; i++) {
385 for (lane = 0; lane < 8; lane++)
386 write_500(info, channel,
387 info->training.lane_timings[i +
388 1][channel][slot]
389 [rank][lane], get_timing_register_addr(lane,
390 i + 1,
391 slot,
392 rank),
393 9, 0);
394 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
395 }
396
397 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200398 MCHBAR8(0x5ff) = 0x0;
399 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100400 write_1d0(0x2, 0x142, 3, 1);
401 for (lane = 0; lane < 8; lane++) {
402 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
403 info->training.lane_timings[2][channel][slot][rank][lane] =
404 read_500(info, channel,
405 get_timing_register_addr(lane, 2, slot, rank), 9);
406 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
407 info->training.lane_timings[3][channel][slot][rank][lane] =
408 info->training.lane_timings[2][channel][slot][rank][lane] +
409 0x20;
410 }
411}
412
413static int count_ranks_in_channel(struct raminfo *info, int channel)
414{
415 int slot, rank;
416 int res = 0;
417 for (slot = 0; slot < NUM_SLOTS; slot++)
418 for (rank = 0; rank < NUM_SLOTS; rank++)
419 res += info->populated_ranks[channel][slot][rank];
420 return res;
421}
422
423static void
424config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
425{
426 int add;
427
428 write_1d0(0, 0x178, 7, 1);
429 seq9(info, channel, slot, rank);
430 program_timings(info, 0x80, channel, slot, rank);
431
432 if (channel == 0)
433 add = count_ranks_in_channel(info, 1);
434 else
435 add = 0;
436 if (!s3resume)
437 gav(rw_test(rank + add));
438 program_timings(info, 0x00, channel, slot, rank);
439 if (!s3resume)
440 gav(rw_test(rank + add));
441 if (!s3resume)
442 gav(rw_test(rank + add));
443 write_1d0(0, 0x142, 3, 1);
444 write_1d0(0, 0x103, 6, 1);
445
446 gav(get_580(channel, 0xc | (rank << 5)));
447 gav(read_1d0(0x142, 3));
448
Felix Held04be2dd2018-07-29 04:53:22 +0200449 MCHBAR8(0x5ff) = 0x0;
450 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100451}
452
453static void set_4cf(struct raminfo *info, int channel, u8 val)
454{
455 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
456 write_500(info, channel, val, 0x4cf, 4, 1);
457 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
458 write_500(info, channel, val, 0x659, 4, 1);
459 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
460 write_500(info, channel, val, 0x697, 4, 1);
461}
462
463static void set_334(int zero)
464{
465 int j, k, channel;
466 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
467 u32 vd8[2][16];
468
469 for (channel = 0; channel < NUM_CHANNELS; channel++) {
470 for (j = 0; j < 4; j++) {
471 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
472 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
473 u16 c;
474 if ((j == 0 || j == 3) && zero)
475 c = 0;
476 else if (j == 3)
477 c = 0x5f;
478 else
479 c = 0x5f5f;
480
481 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32(0x138 + 8 * k) =
483 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200487 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100488 }
489
Felix Held22ca8cb2018-07-29 05:09:44 +0200490 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200492 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
493 zero ? 0 : (0x18191819 & lmask);
494 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
495 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
496 zero ? 0 : (a & lmask);
497 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
498 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499 }
500 }
501
Felix Held04be2dd2018-07-29 04:53:22 +0200502 MCHBAR32_OR(0x130, 1);
503 while (MCHBAR8(0x130) & 1)
504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100505}
506
507static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
508{
509 u32 v;
510 v = read_1d0(addr, split);
511 write_1d0((v & and) | or, addr, split, flag);
512}
513
514static int find_highest_bit_set(u16 val)
515{
516 int i;
517 for (i = 15; i >= 0; i--)
518 if (val & (1 << i))
519 return i;
520 return -1;
521}
522
523static int find_lowest_bit_set32(u32 val)
524{
525 int i;
526 for (i = 0; i < 32; i++)
527 if (val & (1 << i))
528 return i;
529 return -1;
530}
531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100532enum {
533 DEVICE_TYPE = 2,
534 MODULE_TYPE = 3,
535 DENSITY = 4,
536 RANKS_AND_DQ = 7,
537 MEMORY_BUS_WIDTH = 8,
538 TIMEBASE_DIVIDEND = 10,
539 TIMEBASE_DIVISOR = 11,
540 CYCLETIME = 12,
541
542 CAS_LATENCIES_LSB = 14,
543 CAS_LATENCIES_MSB = 15,
544 CAS_LATENCY_TIME = 16,
545 THERMAL_AND_REFRESH = 31,
546 REFERENCE_RAW_CARD_USED = 62,
547 RANK1_ADDRESS_MAPPING = 63
548};
549
550static void calculate_timings(struct raminfo *info)
551{
552 unsigned cycletime;
553 unsigned cas_latency_time;
554 unsigned supported_cas_latencies;
555 unsigned channel, slot;
556 unsigned clock_speed_index;
557 unsigned min_cas_latency;
558 unsigned cas_latency;
559 unsigned max_clock_index;
560
561 /* Find common CAS latency */
562 supported_cas_latencies = 0x3fe;
563 for (channel = 0; channel < NUM_CHANNELS; channel++)
564 for (slot = 0; slot < NUM_SLOTS; slot++)
565 if (info->populated_ranks[channel][slot][0])
566 supported_cas_latencies &=
567 2 *
568 (info->
569 spd[channel][slot][CAS_LATENCIES_LSB] |
570 (info->
571 spd[channel][slot][CAS_LATENCIES_MSB] <<
572 8));
573
574 max_clock_index = min(3, info->max_supported_clock_speed_index);
575
576 cycletime = min_cycletime[max_clock_index];
577 cas_latency_time = min_cas_latency_time[max_clock_index];
578
579 for (channel = 0; channel < NUM_CHANNELS; channel++)
580 for (slot = 0; slot < NUM_SLOTS; slot++)
581 if (info->populated_ranks[channel][slot][0]) {
582 unsigned timebase;
583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
589 max(cycletime,
590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
593 max(cas_latency_time,
594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
598 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
599 if (cycletime == min_cycletime[clock_speed_index])
600 break;
601 if (cycletime > min_cycletime[clock_speed_index]) {
602 clock_speed_index--;
603 cycletime = min_cycletime[clock_speed_index];
604 break;
605 }
606 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100607 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100608 cas_latency = 0;
609 while (supported_cas_latencies) {
610 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
611 if (cas_latency <= min_cas_latency)
612 break;
613 supported_cas_latencies &=
614 ~(1 << find_highest_bit_set(supported_cas_latencies));
615 }
616
617 if (cas_latency != min_cas_latency && clock_speed_index)
618 clock_speed_index--;
619
620 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
621 die("Couldn't configure DRAM");
622 info->clock_speed_index = clock_speed_index;
623 info->cas_latency = cas_latency;
624}
625
626static void program_base_timings(struct raminfo *info)
627{
628 unsigned channel;
629 unsigned slot, rank, lane;
630 unsigned extended_silicon_revision;
631 int i;
632
633 extended_silicon_revision = info->silicon_revision;
634 if (info->silicon_revision == 0)
635 for (channel = 0; channel < NUM_CHANNELS; channel++)
636 for (slot = 0; slot < NUM_SLOTS; slot++)
637 if ((info->
638 spd[channel][slot][MODULE_TYPE] & 0xF) ==
639 3)
640 extended_silicon_revision = 4;
641
642 for (channel = 0; channel < NUM_CHANNELS; channel++) {
643 for (slot = 0; slot < NUM_SLOTS; slot++)
644 for (rank = 0; rank < NUM_SLOTS; rank++) {
645 int card_timing_2;
646 if (!info->populated_ranks[channel][slot][rank])
647 continue;
648
649 for (lane = 0; lane < 9; lane++) {
650 int tm_reg;
651 int card_timing;
652
653 card_timing = 0;
654 if ((info->
655 spd[channel][slot][MODULE_TYPE] &
656 0xF) == 3) {
657 int reference_card;
658 reference_card =
659 info->
660 spd[channel][slot]
661 [REFERENCE_RAW_CARD_USED] &
662 0x1f;
663 if (reference_card == 3)
664 card_timing =
665 u16_ffd1188[0][lane]
666 [info->
667 clock_speed_index];
668 if (reference_card == 5)
669 card_timing =
670 u16_ffd1188[1][lane]
671 [info->
672 clock_speed_index];
673 }
674
675 info->training.
676 lane_timings[0][channel][slot][rank]
677 [lane] =
678 u8_FFFD1218[info->
679 clock_speed_index];
680 info->training.
681 lane_timings[1][channel][slot][rank]
682 [lane] = 256;
683
684 for (tm_reg = 2; tm_reg < 4; tm_reg++)
685 info->training.
686 lane_timings[tm_reg]
687 [channel][slot][rank][lane]
688 =
689 u8_FFFD1240[channel]
690 [extended_silicon_revision]
691 [lane][2 * slot +
692 rank][info->
693 clock_speed_index]
694 + info->max4048[channel]
695 +
696 u8_FFFD0C78[channel]
697 [extended_silicon_revision]
698 [info->
699 mode4030[channel]][slot]
700 [rank][info->
701 clock_speed_index]
702 + card_timing;
703 for (tm_reg = 0; tm_reg < 4; tm_reg++)
704 write_500(info, channel,
705 info->training.
706 lane_timings[tm_reg]
707 [channel][slot][rank]
708 [lane],
709 get_timing_register_addr
710 (lane, tm_reg, slot,
711 rank), 9, 0);
712 }
713
714 card_timing_2 = 0;
715 if (!(extended_silicon_revision != 4
716 || (info->
717 populated_ranks_mask[channel] & 5) ==
718 5)) {
719 if ((info->
720 spd[channel][slot]
721 [REFERENCE_RAW_CARD_USED] & 0x1F)
722 == 3)
723 card_timing_2 =
724 u16_FFFE0EB8[0][info->
725 clock_speed_index];
726 if ((info->
727 spd[channel][slot]
728 [REFERENCE_RAW_CARD_USED] & 0x1F)
729 == 5)
730 card_timing_2 =
731 u16_FFFE0EB8[1][info->
732 clock_speed_index];
733 }
734
735 for (i = 0; i < 3; i++)
736 write_500(info, channel,
737 (card_timing_2 +
738 info->max4048[channel]
739 +
740 u8_FFFD0EF8[channel]
741 [extended_silicon_revision]
742 [info->
743 mode4030[channel]][info->
744 clock_speed_index]),
745 u16_fffd0c50[i][slot][rank],
746 8, 1);
747 write_500(info, channel,
748 (info->max4048[channel] +
749 u8_FFFD0C78[channel]
750 [extended_silicon_revision][info->
751 mode4030
752 [channel]]
753 [slot][rank][info->
754 clock_speed_index]),
755 u16_fffd0c70[slot][rank], 7, 1);
756 }
757 if (!info->populated_ranks_mask[channel])
758 continue;
759 for (i = 0; i < 3; i++)
760 write_500(info, channel,
761 (info->max4048[channel] +
762 info->avg4044[channel]
763 +
764 u8_FFFD17E0[channel]
765 [extended_silicon_revision][info->
766 mode4030
767 [channel]][info->
768 clock_speed_index]),
769 u16_fffd0c68[i], 8, 1);
770 }
771}
772
773static unsigned int fsbcycle_ps(struct raminfo *info)
774{
775 return 900000 / info->fsb_frequency;
776}
777
778/* The time of DDR transfer in ps. */
779static unsigned int halfcycle_ps(struct raminfo *info)
780{
781 return 3750 / (info->clock_speed_index + 3);
782}
783
784/* The time of clock cycle in ps. */
785static unsigned int cycle_ps(struct raminfo *info)
786{
787 return 2 * halfcycle_ps(info);
788}
789
790/* Frequency in 1.(1)=10/9 MHz units. */
791static unsigned frequency_11(struct raminfo *info)
792{
793 return (info->clock_speed_index + 3) * 120;
794}
795
796/* Frequency in 0.1 MHz units. */
797static unsigned frequency_01(struct raminfo *info)
798{
799 return 100 * frequency_11(info) / 9;
800}
801
802static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
803{
804 return (frequency_11(info) * 2) * ps / 900000;
805}
806
807static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
808{
809 return (frequency_11(info)) * ns / 900;
810}
811
812static void compute_derived_timings(struct raminfo *info)
813{
814 unsigned channel, slot, rank;
815 int extended_silicon_revision;
816 int some_delay_1_ps;
817 int some_delay_2_ps;
818 int some_delay_2_halfcycles_ceil;
819 int some_delay_2_halfcycles_floor;
820 int some_delay_3_ps;
821 int some_delay_3_halfcycles;
822 int some_delay_3_ps_rounded;
823 int some_delay_1_cycle_ceil;
824 int some_delay_1_cycle_floor;
825
826 some_delay_3_halfcycles = 0;
827 some_delay_3_ps_rounded = 0;
828 extended_silicon_revision = info->silicon_revision;
829 if (!info->silicon_revision)
830 for (channel = 0; channel < NUM_CHANNELS; channel++)
831 for (slot = 0; slot < NUM_SLOTS; slot++)
832 if ((info->
833 spd[channel][slot][MODULE_TYPE] & 0xF) ==
834 3)
835 extended_silicon_revision = 4;
836 if (info->board_lane_delay[7] < 5)
837 info->board_lane_delay[7] = 5;
838 info->revision_flag_1 = 2;
839 if (info->silicon_revision == 2 || info->silicon_revision == 3)
840 info->revision_flag_1 = 0;
841 if (info->revision < 16)
842 info->revision_flag_1 = 0;
843
844 if (info->revision < 8)
845 info->revision_flag_1 = 0;
846 if (info->revision >= 8 && (info->silicon_revision == 0
847 || info->silicon_revision == 1))
848 some_delay_2_ps = 735;
849 else
850 some_delay_2_ps = 750;
851
852 if (info->revision >= 0x10 && (info->silicon_revision == 0
853 || info->silicon_revision == 1))
854 some_delay_1_ps = 3929;
855 else
856 some_delay_1_ps = 3490;
857
858 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
859 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
860 if (some_delay_1_ps % cycle_ps(info))
861 some_delay_1_cycle_ceil++;
862 else
863 some_delay_1_cycle_floor--;
864 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
865 if (info->revision_flag_1)
866 some_delay_2_ps = halfcycle_ps(info) >> 6;
867 some_delay_2_ps +=
868 max(some_delay_1_ps - 30,
869 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
870 375;
871 some_delay_3_ps =
872 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
873 if (info->revision_flag_1) {
874 if (some_delay_3_ps < 150)
875 some_delay_3_halfcycles = 0;
876 else
877 some_delay_3_halfcycles =
878 (some_delay_3_ps << 6) / halfcycle_ps(info);
879 some_delay_3_ps_rounded =
880 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
881 }
882 some_delay_2_halfcycles_ceil =
883 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
884 2 * (some_delay_1_cycle_ceil - 1);
885 if (info->revision_flag_1 && some_delay_3_ps < 150)
886 some_delay_2_halfcycles_ceil++;
887 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
888 if (info->revision < 0x10)
889 some_delay_2_halfcycles_floor =
890 some_delay_2_halfcycles_ceil - 1;
891 if (!info->revision_flag_1)
892 some_delay_2_halfcycles_floor++;
893 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
894 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
895 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
896 || (info->populated_ranks[1][0][0]
897 && info->populated_ranks[1][1][0]))
898 info->max_slots_used_in_channel = 2;
899 else
900 info->max_slots_used_in_channel = 1;
901 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200902 MCHBAR32(0x244 + (channel << 10)) =
903 ((info->revision < 8) ? 1 : 0x200) |
904 ((2 - info->max_slots_used_in_channel) << 17) |
905 (channel << 21) |
906 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100907 if (info->max_slots_used_in_channel == 1) {
908 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
909 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
910 } else {
911 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
912 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
913 || (count_ranks_in_channel(info, 1) ==
914 2)) ? 2 : 3;
915 }
916 for (channel = 0; channel < NUM_CHANNELS; channel++) {
917 int max_of_unk;
918 int min_of_unk_2;
919
920 int i, count;
921 int sum;
922
923 if (!info->populated_ranks_mask[channel])
924 continue;
925
926 max_of_unk = 0;
927 min_of_unk_2 = 32767;
928
929 sum = 0;
930 count = 0;
931 for (i = 0; i < 3; i++) {
932 int unk1;
933 if (info->revision < 8)
934 unk1 =
935 u8_FFFD1891[0][channel][info->
936 clock_speed_index]
937 [i];
938 else if (!
939 (info->revision >= 0x10
940 || info->revision_flag_1))
941 unk1 =
942 u8_FFFD1891[1][channel][info->
943 clock_speed_index]
944 [i];
945 else
946 unk1 = 0;
947 for (slot = 0; slot < NUM_SLOTS; slot++)
948 for (rank = 0; rank < NUM_RANKS; rank++) {
949 int a = 0;
950 int b = 0;
951
952 if (!info->
953 populated_ranks[channel][slot]
954 [rank])
955 continue;
956 if (extended_silicon_revision == 4
957 && (info->
958 populated_ranks_mask[channel] &
959 5) != 5) {
960 if ((info->
961 spd[channel][slot]
962 [REFERENCE_RAW_CARD_USED] &
963 0x1F) == 3) {
964 a = u16_ffd1178[0]
965 [info->
966 clock_speed_index];
967 b = u16_fe0eb8[0][info->
968 clock_speed_index];
969 } else
970 if ((info->
971 spd[channel][slot]
972 [REFERENCE_RAW_CARD_USED]
973 & 0x1F) == 5) {
974 a = u16_ffd1178[1]
975 [info->
976 clock_speed_index];
977 b = u16_fe0eb8[1][info->
978 clock_speed_index];
979 }
980 }
981 min_of_unk_2 = min(min_of_unk_2, a);
982 min_of_unk_2 = min(min_of_unk_2, b);
983 if (rank == 0) {
984 sum += a;
985 count++;
986 }
987 {
988 int t;
989 t = b +
990 u8_FFFD0EF8[channel]
991 [extended_silicon_revision]
992 [info->
993 mode4030[channel]][info->
994 clock_speed_index];
995 if (unk1 >= t)
996 max_of_unk =
997 max(max_of_unk,
998 unk1 - t);
999 }
1000 }
1001 {
1002 int t =
1003 u8_FFFD17E0[channel]
1004 [extended_silicon_revision][info->
1005 mode4030
1006 [channel]]
1007 [info->clock_speed_index] + min_of_unk_2;
1008 if (unk1 >= t)
1009 max_of_unk = max(max_of_unk, unk1 - t);
1010 }
1011 }
1012
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 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002239 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002240
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002241 for (i = 0; i < 8; i++)
2242 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002243
2244 if (!first_run) {
2245 int is_all_ok = 1;
2246 for (lane = 0; lane < 8; lane++)
2247 if (timings[reg_178][channel][slot][rank][lane].
2248 smallest ==
2249 timings[reg_178][channel][slot][rank][lane].
2250 largest) {
2251 timings[reg_178][channel][slot][rank][lane].
2252 smallest = 0;
2253 timings[reg_178][channel][slot][rank][lane].
2254 largest = 0;
2255 is_all_ok = 0;
2256 }
2257 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002258 for (i = 0; i < 8; i++)
2259 state[i] = COMPLETE;
2260 }
2261 }
2262
2263 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2264 u8 failmask = 0;
2265 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2266 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2267 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002268 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002269 do_fsm(state, count, failmask, 5, 47, lower_usable,
2270 upper_usable, reg1b3);
2271 }
2272
2273 if (reg1b3) {
2274 write_1d0(0, 0x1b3, 6, 1);
2275 write_1d0(0, 0x1a3, 6, 1);
2276 for (lane = 0; lane < 8; lane++) {
2277 if (state[lane] == COMPLETE) {
2278 timings[reg_178][channel][slot][rank][lane].
2279 smallest =
2280 lower_usable[lane] +
2281 (info->training.
2282 lane_timings[0][channel][slot][rank][lane]
2283 & 0x3F) - 32;
2284 timings[reg_178][channel][slot][rank][lane].
2285 largest =
2286 upper_usable[lane] +
2287 (info->training.
2288 lane_timings[0][channel][slot][rank][lane]
2289 & 0x3F) - 32;
2290 }
2291 }
2292 }
2293
2294 if (!first_run) {
2295 for (lane = 0; lane < 8; lane++)
2296 if (state[lane] == COMPLETE) {
2297 write_500(info, channel,
2298 timings[reg_178][channel][slot][rank]
2299 [lane].smallest,
2300 get_timing_register_addr(lane, 0,
2301 slot, rank),
2302 9, 1);
2303 write_500(info, channel,
2304 timings[reg_178][channel][slot][rank]
2305 [lane].smallest +
2306 info->training.
2307 lane_timings[1][channel][slot][rank]
2308 [lane]
2309 -
2310 info->training.
2311 lane_timings[0][channel][slot][rank]
2312 [lane], get_timing_register_addr(lane,
2313 1,
2314 slot,
2315 rank),
2316 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002317 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002318 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002319 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002320
2321 do {
2322 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002323 for (i = 0; i < niter; i++) {
2324 if (failmask == 0xFF)
2325 break;
2326 failmask |=
2327 check_testing_type2(info, total_rank, 2, i,
2328 0);
2329 failmask |=
2330 check_testing_type2(info, total_rank, 3, i,
2331 1);
2332 }
Felix Held04be2dd2018-07-29 04:53:22 +02002333 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002335 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002336 if ((1 << lane) & failmask) {
2337 if (timings[reg_178][channel]
2338 [slot][rank][lane].
2339 largest <=
2340 timings[reg_178][channel]
2341 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002342 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002343 [lane] = -1;
2344 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002345 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002346 [lane] = 0;
2347 timings[reg_178]
2348 [channel][slot]
2349 [rank][lane].
2350 smallest++;
2351 write_500(info, channel,
2352 timings
2353 [reg_178]
2354 [channel]
2355 [slot][rank]
2356 [lane].
2357 smallest,
2358 get_timing_register_addr
2359 (lane, 0,
2360 slot, rank),
2361 9, 1);
2362 write_500(info, channel,
2363 timings
2364 [reg_178]
2365 [channel]
2366 [slot][rank]
2367 [lane].
2368 smallest +
2369 info->
2370 training.
2371 lane_timings
2372 [1][channel]
2373 [slot][rank]
2374 [lane]
2375 -
2376 info->
2377 training.
2378 lane_timings
2379 [0][channel]
2380 [slot][rank]
2381 [lane],
2382 get_timing_register_addr
2383 (lane, 1,
2384 slot, rank),
2385 9, 1);
2386 }
2387 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002388 num_successfully_checked[lane]
2389 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002390 }
2391 }
Felix Held04be2dd2018-07-29 04:53:22 +02002392 while (!check_bounded(num_successfully_checked, 2))
2393 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002394
2395 for (lane = 0; lane < 8; lane++)
2396 if (state[lane] == COMPLETE) {
2397 write_500(info, channel,
2398 timings[reg_178][channel][slot][rank]
2399 [lane].largest,
2400 get_timing_register_addr(lane, 0,
2401 slot, rank),
2402 9, 1);
2403 write_500(info, channel,
2404 timings[reg_178][channel][slot][rank]
2405 [lane].largest +
2406 info->training.
2407 lane_timings[1][channel][slot][rank]
2408 [lane]
2409 -
2410 info->training.
2411 lane_timings[0][channel][slot][rank]
2412 [lane], get_timing_register_addr(lane,
2413 1,
2414 slot,
2415 rank),
2416 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002417 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002418 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002419 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002420
2421 do {
2422 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423 for (i = 0; i < niter; i++) {
2424 if (failmask == 0xFF)
2425 break;
2426 failmask |=
2427 check_testing_type2(info, total_rank, 2, i,
2428 0);
2429 failmask |=
2430 check_testing_type2(info, total_rank, 3, i,
2431 1);
2432 }
2433
Felix Held04be2dd2018-07-29 04:53:22 +02002434 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002435 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002436 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002437 if ((1 << lane) & failmask) {
2438 if (timings[reg_178][channel]
2439 [slot][rank][lane].
2440 largest <=
2441 timings[reg_178][channel]
2442 [slot][rank][lane].
2443 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002444 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002445 [lane] = -1;
2446 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002447 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002448 [lane] = 0;
2449 timings[reg_178]
2450 [channel][slot]
2451 [rank][lane].
2452 largest--;
2453 write_500(info, channel,
2454 timings
2455 [reg_178]
2456 [channel]
2457 [slot][rank]
2458 [lane].
2459 largest,
2460 get_timing_register_addr
2461 (lane, 0,
2462 slot, rank),
2463 9, 1);
2464 write_500(info, channel,
2465 timings
2466 [reg_178]
2467 [channel]
2468 [slot][rank]
2469 [lane].
2470 largest +
2471 info->
2472 training.
2473 lane_timings
2474 [1][channel]
2475 [slot][rank]
2476 [lane]
2477 -
2478 info->
2479 training.
2480 lane_timings
2481 [0][channel]
2482 [slot][rank]
2483 [lane],
2484 get_timing_register_addr
2485 (lane, 1,
2486 slot, rank),
2487 9, 1);
2488 }
2489 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002490 num_successfully_checked[lane]
2491 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002492 }
2493 }
2494 }
Felix Held04be2dd2018-07-29 04:53:22 +02002495 while (!check_bounded(num_successfully_checked, 3))
2496 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002497
2498 for (lane = 0; lane < 8; lane++) {
2499 write_500(info, channel,
2500 info->training.
2501 lane_timings[0][channel][slot][rank][lane],
2502 get_timing_register_addr(lane, 0, slot, rank),
2503 9, 1);
2504 write_500(info, channel,
2505 info->training.
2506 lane_timings[1][channel][slot][rank][lane],
2507 get_timing_register_addr(lane, 1, slot, rank),
2508 9, 1);
2509 if (timings[reg_178][channel][slot][rank][lane].
2510 largest <=
2511 timings[reg_178][channel][slot][rank][lane].
2512 smallest) {
2513 timings[reg_178][channel][slot][rank][lane].
2514 largest = 0;
2515 timings[reg_178][channel][slot][rank][lane].
2516 smallest = 0;
2517 }
2518 }
2519 }
2520}
2521
2522static void set_10b(struct raminfo *info, u8 val)
2523{
2524 int channel;
2525 int slot, rank;
2526 int lane;
2527
2528 if (read_1d0(0x10b, 6) == val)
2529 return;
2530
2531 write_1d0(val, 0x10b, 6, 1);
2532
2533 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2534 u16 reg_500;
2535 reg_500 = read_500(info, channel,
2536 get_timing_register_addr(lane, 0, slot,
2537 rank), 9);
2538 if (val == 1) {
2539 if (lut16[info->clock_speed_index] <= reg_500)
2540 reg_500 -= lut16[info->clock_speed_index];
2541 else
2542 reg_500 = 0;
2543 } else {
2544 reg_500 += lut16[info->clock_speed_index];
2545 }
2546 write_500(info, channel, reg_500,
2547 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2548 }
2549}
2550
2551static void set_ecc(int onoff)
2552{
2553 int channel;
2554 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2555 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002556 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002557 if (onoff)
2558 t |= 1;
2559 else
2560 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002561 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002562 }
2563}
2564
2565static void set_178(u8 val)
2566{
2567 if (val >= 31)
2568 val = val - 31;
2569 else
2570 val = 63 - val;
2571
2572 write_1d0(2 * val, 0x178, 7, 1);
2573}
2574
2575static void
2576write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2577 int type)
2578{
2579 int lane;
2580
2581 for (lane = 0; lane < 8; lane++)
2582 write_500(info, channel,
2583 info->training.
2584 lane_timings[type][channel][slot][rank][lane],
2585 get_timing_register_addr(lane, type, slot, rank), 9,
2586 0);
2587}
2588
2589static void
2590try_timing_offsets(struct raminfo *info, int channel,
2591 int slot, int rank, int totalrank)
2592{
2593 u16 count[8];
2594 enum state state[8];
2595 u8 lower_usable[8], upper_usable[8];
2596 int lane;
2597 int i;
2598 int flip = 1;
2599 int timing_offset;
2600
2601 for (i = 0; i < 8; i++)
2602 state[i] = BEFORE_USABLE;
2603
2604 memset(count, 0, sizeof(count));
2605
2606 for (lane = 0; lane < 8; lane++)
2607 write_500(info, channel,
2608 info->training.
2609 lane_timings[2][channel][slot][rank][lane] + 32,
2610 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2611
2612 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2613 timing_offset++) {
2614 u8 failmask;
2615 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2616 failmask = 0;
2617 for (i = 0; i < 2 && failmask != 0xff; i++) {
2618 flip = !flip;
2619 write_testing(info, totalrank, flip);
2620 failmask |= check_testing(info, totalrank, flip);
2621 }
2622 do_fsm(state, count, failmask, 10, 63, lower_usable,
2623 upper_usable, timing_offset);
2624 }
2625 write_1d0(0, 0x1bb, 6, 1);
2626 dump_timings(info);
2627 if (!validate_state(state))
2628 die("Couldn't discover DRAM timings (1)\n");
2629
2630 for (lane = 0; lane < 8; lane++) {
2631 u8 bias = 0;
2632
2633 if (info->silicon_revision) {
2634 int usable_length;
2635
2636 usable_length = upper_usable[lane] - lower_usable[lane];
2637 if (usable_length >= 20) {
2638 bias = usable_length / 2 - 10;
2639 if (bias >= 2)
2640 bias = 2;
2641 }
2642 }
2643 write_500(info, channel,
2644 info->training.
2645 lane_timings[2][channel][slot][rank][lane] +
2646 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2647 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2648 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2649 info->training.lane_timings[2][channel][slot][rank][lane] +
2650 lower_usable[lane];
2651 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2652 info->training.lane_timings[2][channel][slot][rank][lane] +
2653 upper_usable[lane];
2654 info->training.timing2_offset[channel][slot][rank][lane] =
2655 info->training.lane_timings[2][channel][slot][rank][lane];
2656 }
2657}
2658
2659static u8
2660choose_training(struct raminfo *info, int channel, int slot, int rank,
2661 int lane, timing_bounds_t * timings, u8 center_178)
2662{
2663 u16 central_weight;
2664 u16 side_weight;
2665 unsigned int sum = 0, count = 0;
2666 u8 span;
2667 u8 lower_margin, upper_margin;
2668 u8 reg_178;
2669 u8 result;
2670
2671 span = 12;
2672 central_weight = 20;
2673 side_weight = 20;
2674 if (info->silicon_revision == 1 && channel == 1) {
2675 central_weight = 5;
2676 side_weight = 20;
2677 if ((info->
2678 populated_ranks_mask[1] ^ (info->
2679 populated_ranks_mask[1] >> 2)) &
2680 1)
2681 span = 18;
2682 }
2683 if ((info->populated_ranks_mask[0] & 5) == 5) {
2684 central_weight = 20;
2685 side_weight = 20;
2686 }
2687 if (info->clock_speed_index >= 2
2688 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2689 if (info->silicon_revision == 1) {
2690 switch (channel) {
2691 case 0:
2692 if (lane == 1) {
2693 central_weight = 10;
2694 side_weight = 20;
2695 }
2696 break;
2697 case 1:
2698 if (lane == 6) {
2699 side_weight = 5;
2700 central_weight = 20;
2701 }
2702 break;
2703 }
2704 }
2705 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2706 side_weight = 5;
2707 central_weight = 20;
2708 }
2709 }
2710 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2711 reg_178 += span) {
2712 u8 smallest;
2713 u8 largest;
2714 largest = timings[reg_178][channel][slot][rank][lane].largest;
2715 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2716 if (largest - smallest + 1 >= 5) {
2717 unsigned int weight;
2718 if (reg_178 == center_178)
2719 weight = central_weight;
2720 else
2721 weight = side_weight;
2722 sum += weight * (largest + smallest);
2723 count += weight;
2724 }
2725 }
2726 dump_timings(info);
2727 if (count == 0)
2728 die("Couldn't discover DRAM timings (2)\n");
2729 result = sum / (2 * count);
2730 lower_margin =
2731 result - timings[center_178][channel][slot][rank][lane].smallest;
2732 upper_margin =
2733 timings[center_178][channel][slot][rank][lane].largest - result;
2734 if (upper_margin < 10 && lower_margin > 10)
2735 result -= min(lower_margin - 10, 10 - upper_margin);
2736 if (upper_margin > 10 && lower_margin < 10)
2737 result += min(upper_margin - 10, 10 - lower_margin);
2738 return result;
2739}
2740
2741#define STANDARD_MIN_MARGIN 5
2742
2743static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2744{
2745 u16 margin[64];
2746 int lane, rank, slot, channel;
2747 u8 reg178;
2748 int count = 0, sum = 0;
2749
2750 for (reg178 = reg178_min[info->clock_speed_index];
2751 reg178 < reg178_max[info->clock_speed_index];
2752 reg178 += reg178_step[info->clock_speed_index]) {
2753 margin[reg178] = -1;
2754 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2755 int curmargin =
2756 timings[reg178][channel][slot][rank][lane].largest -
2757 timings[reg178][channel][slot][rank][lane].
2758 smallest + 1;
2759 if (curmargin < margin[reg178])
2760 margin[reg178] = curmargin;
2761 }
2762 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2763 u16 weight;
2764 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2765 sum += weight * reg178;
2766 count += weight;
2767 }
2768 }
2769 dump_timings(info);
2770 if (count == 0)
2771 die("Couldn't discover DRAM timings (3)\n");
2772
2773 u8 threshold;
2774
2775 for (threshold = 30; threshold >= 5; threshold--) {
2776 int usable_length = 0;
2777 int smallest_fount = 0;
2778 for (reg178 = reg178_min[info->clock_speed_index];
2779 reg178 < reg178_max[info->clock_speed_index];
2780 reg178 += reg178_step[info->clock_speed_index])
2781 if (margin[reg178] >= threshold) {
2782 usable_length +=
2783 reg178_step[info->clock_speed_index];
2784 info->training.reg178_largest =
2785 reg178 -
2786 2 * reg178_step[info->clock_speed_index];
2787
2788 if (!smallest_fount) {
2789 smallest_fount = 1;
2790 info->training.reg178_smallest =
2791 reg178 +
2792 reg178_step[info->
2793 clock_speed_index];
2794 }
2795 }
2796 if (usable_length >= 0x21)
2797 break;
2798 }
2799
2800 return sum / count;
2801}
2802
2803static int check_cached_sanity(struct raminfo *info)
2804{
2805 int lane;
2806 int slot, rank;
2807 int channel;
2808
2809 if (!info->cached_training)
2810 return 0;
2811
2812 for (channel = 0; channel < NUM_CHANNELS; channel++)
2813 for (slot = 0; slot < NUM_SLOTS; slot++)
2814 for (rank = 0; rank < NUM_RANKS; rank++)
2815 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2816 u16 cached_value, estimation_value;
2817 cached_value =
2818 info->cached_training->
2819 lane_timings[1][channel][slot][rank]
2820 [lane];
2821 if (cached_value >= 0x18
2822 && cached_value <= 0x1E7) {
2823 estimation_value =
2824 info->training.
2825 lane_timings[1][channel]
2826 [slot][rank][lane];
2827 if (estimation_value <
2828 cached_value - 24)
2829 return 0;
2830 if (estimation_value >
2831 cached_value + 24)
2832 return 0;
2833 }
2834 }
2835 return 1;
2836}
2837
2838static int try_cached_training(struct raminfo *info)
2839{
2840 u8 saved_243[2];
2841 u8 tm;
2842
2843 int channel, slot, rank, lane;
2844 int flip = 1;
2845 int i, j;
2846
2847 if (!check_cached_sanity(info))
2848 return 0;
2849
2850 info->training.reg178_center = info->cached_training->reg178_center;
2851 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2852 info->training.reg178_largest = info->cached_training->reg178_largest;
2853 memcpy(&info->training.timing_bounds,
2854 &info->cached_training->timing_bounds,
2855 sizeof(info->training.timing_bounds));
2856 memcpy(&info->training.timing_offset,
2857 &info->cached_training->timing_offset,
2858 sizeof(info->training.timing_offset));
2859
2860 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002861 saved_243[0] = MCHBAR8(0x243);
2862 saved_243[1] = MCHBAR8(0x643);
2863 MCHBAR8(0x243) = saved_243[0] | 2;
2864 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002865 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002866 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002867 if (read_1d0(0x10b, 6) & 1)
2868 set_10b(info, 0);
2869 for (tm = 0; tm < 2; tm++) {
2870 int totalrank;
2871
2872 set_178(tm ? info->cached_training->reg178_largest : info->
2873 cached_training->reg178_smallest);
2874
2875 totalrank = 0;
2876 /* Check timing ranges. With i == 0 we check smallest one and with
2877 i == 1 the largest bound. With j == 0 we check that on the bound
2878 it still works whereas with j == 1 we check that just outside of
2879 bound we fail.
2880 */
2881 FOR_POPULATED_RANKS_BACKWARDS {
2882 for (i = 0; i < 2; i++) {
2883 for (lane = 0; lane < 8; lane++) {
2884 write_500(info, channel,
2885 info->cached_training->
2886 timing2_bounds[channel][slot]
2887 [rank][lane][i],
2888 get_timing_register_addr(lane,
2889 3,
2890 slot,
2891 rank),
2892 9, 1);
2893
2894 if (!i)
2895 write_500(info, channel,
2896 info->
2897 cached_training->
2898 timing2_offset
2899 [channel][slot][rank]
2900 [lane],
2901 get_timing_register_addr
2902 (lane, 2, slot, rank),
2903 9, 1);
2904 write_500(info, channel,
2905 i ? info->cached_training->
2906 timing_bounds[tm][channel]
2907 [slot][rank][lane].
2908 largest : info->
2909 cached_training->
2910 timing_bounds[tm][channel]
2911 [slot][rank][lane].smallest,
2912 get_timing_register_addr(lane,
2913 0,
2914 slot,
2915 rank),
2916 9, 1);
2917 write_500(info, channel,
2918 info->cached_training->
2919 timing_offset[channel][slot]
2920 [rank][lane] +
2921 (i ? info->cached_training->
2922 timing_bounds[tm][channel]
2923 [slot][rank][lane].
2924 largest : info->
2925 cached_training->
2926 timing_bounds[tm][channel]
2927 [slot][rank][lane].
2928 smallest) - 64,
2929 get_timing_register_addr(lane,
2930 1,
2931 slot,
2932 rank),
2933 9, 1);
2934 }
2935 for (j = 0; j < 2; j++) {
2936 u8 failmask;
2937 u8 expected_failmask;
2938 char reg1b3;
2939
2940 reg1b3 = (j == 1) + 4;
2941 reg1b3 =
2942 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2943 write_1d0(reg1b3, 0x1bb, 6, 1);
2944 write_1d0(reg1b3, 0x1b3, 6, 1);
2945 write_1d0(reg1b3, 0x1a3, 6, 1);
2946
2947 flip = !flip;
2948 write_testing(info, totalrank, flip);
2949 failmask =
2950 check_testing(info, totalrank,
2951 flip);
2952 expected_failmask =
2953 j == 0 ? 0x00 : 0xff;
2954 if (failmask != expected_failmask)
2955 goto fail;
2956 }
2957 }
2958 totalrank++;
2959 }
2960 }
2961
2962 set_178(info->cached_training->reg178_center);
2963 if (info->use_ecc)
2964 set_ecc(1);
2965 write_training_data(info);
2966 write_1d0(0, 322, 3, 1);
2967 info->training = *info->cached_training;
2968
2969 write_1d0(0, 0x1bb, 6, 1);
2970 write_1d0(0, 0x1b3, 6, 1);
2971 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002972 MCHBAR8(0x243) = saved_243[0];
2973 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002974
2975 return 1;
2976
2977fail:
2978 FOR_POPULATED_RANKS {
2979 write_500_timings_type(info, channel, slot, rank, 1);
2980 write_500_timings_type(info, channel, slot, rank, 2);
2981 write_500_timings_type(info, channel, slot, rank, 3);
2982 }
2983
2984 write_1d0(0, 0x1bb, 6, 1);
2985 write_1d0(0, 0x1b3, 6, 1);
2986 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002987 MCHBAR8(0x243) = saved_243[0];
2988 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002989
2990 return 0;
2991}
2992
2993static void do_ram_training(struct raminfo *info)
2994{
2995 u8 saved_243[2];
2996 int totalrank = 0;
2997 u8 reg_178;
2998 int niter;
2999
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003000 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003001 int lane, rank, slot, channel;
3002 u8 reg178_center;
3003
3004 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003005 saved_243[0] = MCHBAR8(0x243);
3006 saved_243[1] = MCHBAR8(0x643);
3007 MCHBAR8(0x243) = saved_243[0] | 2;
3008 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003009 switch (info->clock_speed_index) {
3010 case 0:
3011 niter = 5;
3012 break;
3013 case 1:
3014 niter = 10;
3015 break;
3016 default:
3017 niter = 19;
3018 break;
3019 }
3020 set_ecc(0);
3021
3022 FOR_POPULATED_RANKS_BACKWARDS {
3023 int i;
3024
3025 write_500_timings_type(info, channel, slot, rank, 0);
3026
3027 write_testing(info, totalrank, 0);
3028 for (i = 0; i < niter; i++) {
3029 write_testing_type2(info, totalrank, 2, i, 0);
3030 write_testing_type2(info, totalrank, 3, i, 1);
3031 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003032 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003033 totalrank++;
3034 }
3035
3036 if (reg178_min[info->clock_speed_index] <
3037 reg178_max[info->clock_speed_index])
3038 memset(timings[reg178_min[info->clock_speed_index]], 0,
3039 sizeof(timings[0]) *
3040 (reg178_max[info->clock_speed_index] -
3041 reg178_min[info->clock_speed_index]));
3042 for (reg_178 = reg178_min[info->clock_speed_index];
3043 reg_178 < reg178_max[info->clock_speed_index];
3044 reg_178 += reg178_step[info->clock_speed_index]) {
3045 totalrank = 0;
3046 set_178(reg_178);
3047 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3048 for (slot = 0; slot < NUM_SLOTS; slot++)
3049 for (rank = 0; rank < NUM_RANKS; rank++) {
3050 memset(&timings[reg_178][channel][slot]
3051 [rank][0].smallest, 0, 16);
3052 if (info->
3053 populated_ranks[channel][slot]
3054 [rank]) {
3055 train_ram_at_178(info, channel,
3056 slot, rank,
3057 totalrank,
3058 reg_178, 1,
3059 niter,
3060 timings);
3061 totalrank++;
3062 }
3063 }
3064 }
3065
3066 reg178_center = choose_reg178(info, timings);
3067
3068 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3069 info->training.timing_bounds[0][channel][slot][rank][lane].
3070 smallest =
3071 timings[info->training.
3072 reg178_smallest][channel][slot][rank][lane].
3073 smallest;
3074 info->training.timing_bounds[0][channel][slot][rank][lane].
3075 largest =
3076 timings[info->training.
3077 reg178_smallest][channel][slot][rank][lane].largest;
3078 info->training.timing_bounds[1][channel][slot][rank][lane].
3079 smallest =
3080 timings[info->training.
3081 reg178_largest][channel][slot][rank][lane].smallest;
3082 info->training.timing_bounds[1][channel][slot][rank][lane].
3083 largest =
3084 timings[info->training.
3085 reg178_largest][channel][slot][rank][lane].largest;
3086 info->training.timing_offset[channel][slot][rank][lane] =
3087 info->training.lane_timings[1][channel][slot][rank][lane]
3088 -
3089 info->training.lane_timings[0][channel][slot][rank][lane] +
3090 64;
3091 }
3092
3093 if (info->silicon_revision == 1
3094 && (info->
3095 populated_ranks_mask[1] ^ (info->
3096 populated_ranks_mask[1] >> 2)) & 1) {
3097 int ranks_after_channel1;
3098
3099 totalrank = 0;
3100 for (reg_178 = reg178_center - 18;
3101 reg_178 <= reg178_center + 18; reg_178 += 18) {
3102 totalrank = 0;
3103 set_178(reg_178);
3104 for (slot = 0; slot < NUM_SLOTS; slot++)
3105 for (rank = 0; rank < NUM_RANKS; rank++) {
3106 if (info->
3107 populated_ranks[1][slot][rank]) {
3108 train_ram_at_178(info, 1, slot,
3109 rank,
3110 totalrank,
3111 reg_178, 0,
3112 niter,
3113 timings);
3114 totalrank++;
3115 }
3116 }
3117 }
3118 ranks_after_channel1 = totalrank;
3119
3120 for (reg_178 = reg178_center - 12;
3121 reg_178 <= reg178_center + 12; reg_178 += 12) {
3122 totalrank = ranks_after_channel1;
3123 set_178(reg_178);
3124 for (slot = 0; slot < NUM_SLOTS; slot++)
3125 for (rank = 0; rank < NUM_RANKS; rank++)
3126 if (info->
3127 populated_ranks[0][slot][rank]) {
3128 train_ram_at_178(info, 0, slot,
3129 rank,
3130 totalrank,
3131 reg_178, 0,
3132 niter,
3133 timings);
3134 totalrank++;
3135 }
3136
3137 }
3138 } else {
3139 for (reg_178 = reg178_center - 12;
3140 reg_178 <= reg178_center + 12; reg_178 += 12) {
3141 totalrank = 0;
3142 set_178(reg_178);
3143 FOR_POPULATED_RANKS_BACKWARDS {
3144 train_ram_at_178(info, channel, slot, rank,
3145 totalrank, reg_178, 0, niter,
3146 timings);
3147 totalrank++;
3148 }
3149 }
3150 }
3151
3152 set_178(reg178_center);
3153 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3154 u16 tm0;
3155
3156 tm0 =
3157 choose_training(info, channel, slot, rank, lane, timings,
3158 reg178_center);
3159 write_500(info, channel, tm0,
3160 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3161 write_500(info, channel,
3162 tm0 +
3163 info->training.
3164 lane_timings[1][channel][slot][rank][lane] -
3165 info->training.
3166 lane_timings[0][channel][slot][rank][lane],
3167 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3168 }
3169
3170 totalrank = 0;
3171 FOR_POPULATED_RANKS_BACKWARDS {
3172 try_timing_offsets(info, channel, slot, rank, totalrank);
3173 totalrank++;
3174 }
Felix Held04be2dd2018-07-29 04:53:22 +02003175 MCHBAR8(0x243) = saved_243[0];
3176 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003177 write_1d0(0, 0x142, 3, 1);
3178 info->training.reg178_center = reg178_center;
3179}
3180
3181static void ram_training(struct raminfo *info)
3182{
3183 u16 saved_fc4;
3184
Felix Held04be2dd2018-07-29 04:53:22 +02003185 saved_fc4 = MCHBAR16(0xfc4);
3186 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003187
3188 if (info->revision >= 8)
3189 read_4090(info);
3190
3191 if (!try_cached_training(info))
3192 do_ram_training(info);
3193 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3194 && info->clock_speed_index < 2)
3195 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003196 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003197}
3198
3199static unsigned gcd(unsigned a, unsigned b)
3200{
3201 unsigned t;
3202 if (a > b) {
3203 t = a;
3204 a = b;
3205 b = t;
3206 }
3207 /* invariant a < b. */
3208 while (a) {
3209 t = b % a;
3210 b = a;
3211 a = t;
3212 }
3213 return b;
3214}
3215
3216static inline int div_roundup(int a, int b)
3217{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003218 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003219}
3220
3221static unsigned lcm(unsigned a, unsigned b)
3222{
3223 return (a * b) / gcd(a, b);
3224}
3225
3226struct stru1 {
3227 u8 freqs_reversed;
3228 u8 freq_diff_reduced;
3229 u8 freq_min_reduced;
3230 u8 divisor_f4_to_fmax;
3231 u8 divisor_f3_to_fmax;
3232 u8 freq4_to_max_remainder;
3233 u8 freq3_to_2_remainder;
3234 u8 freq3_to_2_remaindera;
3235 u8 freq4_to_2_remainder;
3236 int divisor_f3_to_f1, divisor_f4_to_f2;
3237 int common_time_unit_ps;
3238 int freq_max_reduced;
3239};
3240
3241static void
3242compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3243 int num_cycles_2, int num_cycles_1, int round_it,
3244 int add_freqs, struct stru1 *result)
3245{
3246 int g;
3247 int common_time_unit_ps;
3248 int freq1_reduced, freq2_reduced;
3249 int freq_min_reduced;
3250 int freq_max_reduced;
3251 int freq3, freq4;
3252
3253 g = gcd(freq1, freq2);
3254 freq1_reduced = freq1 / g;
3255 freq2_reduced = freq2 / g;
3256 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3257 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3258
3259 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3260 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3261 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3262 if (add_freqs) {
3263 freq3 += freq2_reduced;
3264 freq4 += freq1_reduced;
3265 }
3266
3267 if (round_it) {
3268 result->freq3_to_2_remainder = 0;
3269 result->freq3_to_2_remaindera = 0;
3270 result->freq4_to_max_remainder = 0;
3271 result->divisor_f4_to_f2 = 0;
3272 result->divisor_f3_to_f1 = 0;
3273 } else {
3274 if (freq2_reduced < freq1_reduced) {
3275 result->freq3_to_2_remainder =
3276 result->freq3_to_2_remaindera =
3277 freq3 % freq1_reduced - freq1_reduced + 1;
3278 result->freq4_to_max_remainder =
3279 -(freq4 % freq1_reduced);
3280 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3281 result->divisor_f4_to_f2 =
3282 (freq4 -
3283 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3284 result->freq4_to_2_remainder =
3285 -(char)((freq1_reduced - freq2_reduced) +
3286 ((u8) freq4 -
3287 (freq1_reduced -
3288 freq2_reduced)) % (u8) freq2_reduced);
3289 } else {
3290 if (freq2_reduced > freq1_reduced) {
3291 result->freq4_to_max_remainder =
3292 (freq4 % freq2_reduced) - freq2_reduced + 1;
3293 result->freq4_to_2_remainder =
3294 freq4 % freq_max_reduced -
3295 freq_max_reduced + 1;
3296 } else {
3297 result->freq4_to_max_remainder =
3298 -(freq4 % freq2_reduced);
3299 result->freq4_to_2_remainder =
3300 -(char)(freq4 % freq_max_reduced);
3301 }
3302 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3303 result->divisor_f3_to_f1 =
3304 (freq3 -
3305 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3306 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3307 result->freq3_to_2_remaindera =
3308 -(char)((freq_max_reduced - freq_min_reduced) +
3309 (freq3 -
3310 (freq_max_reduced -
3311 freq_min_reduced)) % freq1_reduced);
3312 }
3313 }
3314 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3315 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3316 if (round_it) {
3317 if (freq2_reduced > freq1_reduced) {
3318 if (freq3 % freq_max_reduced)
3319 result->divisor_f3_to_fmax++;
3320 }
3321 if (freq2_reduced < freq1_reduced) {
3322 if (freq4 % freq_max_reduced)
3323 result->divisor_f4_to_fmax++;
3324 }
3325 }
3326 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3327 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3328 result->freq_min_reduced = freq_min_reduced;
3329 result->common_time_unit_ps = common_time_unit_ps;
3330 result->freq_max_reduced = freq_max_reduced;
3331}
3332
3333static void
3334set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3335 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3336 int num_cycles_4, int reverse)
3337{
3338 struct stru1 vv;
3339 char multiplier;
3340
3341 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3342 0, 1, &vv);
3343
3344 multiplier =
3345 div_roundup(max
3346 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3347 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3348 div_roundup(num_cycles_1,
3349 vv.common_time_unit_ps) +
3350 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3351 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3352
3353 u32 y =
3354 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3355 vv.freq_max_reduced * multiplier)
3356 | (vv.
3357 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3358 multiplier) << 16) | ((u8) (vv.
3359 freq_min_reduced
3360 *
3361 multiplier)
3362 << 24);
3363 u32 x =
3364 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3365 divisor_f3_to_f1
3366 << 16)
3367 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3368 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003369 MCHBAR32(reg) = y;
3370 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003371 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003372 MCHBAR32(reg + 4) = y;
3373 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003374 }
3375}
3376
3377static void
3378set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3379 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3380 int num_cycles_4)
3381{
3382 struct stru1 ratios1;
3383 struct stru1 ratios2;
3384
3385 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3386 0, 1, &ratios2);
3387 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3388 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003389 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003390 ratios1.freq4_to_max_remainder | (ratios2.
3391 freq4_to_max_remainder
3392 << 8)
3393 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3394 divisor_f4_to_fmax
3395 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003396 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3397 (ratios2.freq4_to_max_remainder << 8) |
3398 (ratios1.divisor_f4_to_fmax << 16) |
3399 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003400}
3401
3402static void
3403set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3404 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3405{
3406 struct stru1 ratios;
3407
3408 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3409 round_it, add_freqs, &ratios);
3410 switch (mode) {
3411 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003412 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3413 (ratios.freqs_reversed << 8);
3414 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3415 (ratios.freq4_to_max_remainder << 8) |
3416 (ratios.divisor_f3_to_fmax << 16) |
3417 (ratios.divisor_f4_to_fmax << 20) |
3418 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003419 break;
3420
3421 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003422 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3423 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003424 break;
3425
3426 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003427 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3428 (ratios.freq4_to_max_remainder << 8) |
3429 (ratios.divisor_f3_to_fmax << 16) |
3430 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003431 break;
3432
3433 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003434 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3435 (ratios.divisor_f4_to_fmax << 8) |
3436 (ratios.freqs_reversed << 12) |
3437 (ratios.freq_min_reduced << 16) |
3438 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439 break;
3440 }
3441}
3442
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003443static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003444{
3445 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3446 0, 1);
3447 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3448 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3449 1);
3450 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3451 frequency_11(info), 1231, 1524, 0, 1);
3452 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3453 frequency_11(info) / 2, 1278, 2008, 0, 1);
3454 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3455 1167, 1539, 0, 1);
3456 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3457 frequency_11(info) / 2, 1403, 1318, 0, 1);
3458 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3459 1);
3460 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3461 1);
3462 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3463 1, 1);
3464 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3465 1);
3466 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3467 frequency_11(info) / 2, 4000, 0, 0, 0);
3468 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3469 frequency_11(info) / 2, 4000, 4000, 0, 0);
3470
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003471 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003472 printk(RAM_SPEW, "[6dc] <= %x\n",
3473 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003474 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003475 } else
3476 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3477 info->delay46_ps[0], 0,
3478 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003479 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3480 frequency_11(info), 2500, 0, 0, 0);
3481 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3482 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003483 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003484 printk(RAM_SPEW, "[6e8] <= %x\n",
3485 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003486 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003487 } else
3488 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3489 info->delay46_ps[1], 0,
3490 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003491 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3492 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3493 470, 0);
3494 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3495 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3496 454, 459, 0);
3497 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3498 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3499 2588, 0);
3500 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3501 2405, 0);
3502 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3503 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3504 480, 0);
3505 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003506 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3507 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003508}
3509
3510static u16 get_max_timing(struct raminfo *info, int channel)
3511{
3512 int slot, rank, lane;
3513 u16 ret = 0;
3514
Felix Held04be2dd2018-07-29 04:53:22 +02003515 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516 return 384;
3517
3518 if (info->revision < 8)
3519 return 256;
3520
3521 for (slot = 0; slot < NUM_SLOTS; slot++)
3522 for (rank = 0; rank < NUM_RANKS; rank++)
3523 if (info->populated_ranks[channel][slot][rank])
3524 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3525 ret = max(ret, read_500(info, channel,
3526 get_timing_register_addr
3527 (lane, 0, slot,
3528 rank), 9));
3529 return ret;
3530}
3531
3532static void set_274265(struct raminfo *info)
3533{
3534 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3535 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3536 int delay_e_over_cycle_ps;
3537 int cycletime_ps;
3538 int channel;
3539
3540 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003541 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003542 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3543 cycletime_ps =
3544 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3545 delay_d_ps =
3546 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3547 - info->some_delay_3_ps_rounded + 200;
3548 if (!
3549 ((info->silicon_revision == 0
3550 || info->silicon_revision == 1)
3551 && (info->revision >= 8)))
3552 delay_d_ps += halfcycle_ps(info) * 2;
3553 delay_d_ps +=
3554 halfcycle_ps(info) * (!info->revision_flag_1 +
3555 info->some_delay_2_halfcycles_ceil +
3556 2 * info->some_delay_1_cycle_floor +
3557 info->clock_speed_index +
3558 2 * info->cas_latency - 7 + 11);
3559 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3560
Felix Held04be2dd2018-07-29 04:53:22 +02003561 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3562 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3563 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003564 delay_d_ps += 650;
3565 delay_c_ps = delay_d_ps + 1800;
3566 if (delay_c_ps <= delay_a_ps)
3567 delay_e_ps = 0;
3568 else
3569 delay_e_ps =
3570 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3571 cycletime_ps);
3572
3573 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3574 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3575 delay_f_cycles =
3576 div_roundup(2500 - delay_e_over_cycle_ps,
3577 2 * halfcycle_ps(info));
3578 if (delay_f_cycles > delay_e_cycles) {
3579 info->delay46_ps[channel] = delay_e_ps;
3580 delay_e_cycles = 0;
3581 } else {
3582 info->delay46_ps[channel] =
3583 delay_e_over_cycle_ps +
3584 2 * halfcycle_ps(info) * delay_f_cycles;
3585 delay_e_cycles -= delay_f_cycles;
3586 }
3587
3588 if (info->delay46_ps[channel] < 2500) {
3589 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003590 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003591 }
3592 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3593 if (delay_b_ps <= delay_a_ps)
3594 delay_b_ps = 0;
3595 else
3596 delay_b_ps -= delay_a_ps;
3597 info->delay54_ps[channel] =
3598 cycletime_ps * div_roundup(delay_b_ps,
3599 cycletime_ps) -
3600 2 * halfcycle_ps(info) * delay_e_cycles;
3601 if (info->delay54_ps[channel] < 2500)
3602 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003603 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003604 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3605 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003606 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003607 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003608 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003609 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3610 4 * halfcycle_ps(info)) - 6;
3611 MCHBAR32((channel << 10) + 0x274) =
3612 info->training.reg274265[channel][1] |
3613 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003614 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003615 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3616 4 * halfcycle_ps(info)) + 1;
3617 MCHBAR16((channel << 10) + 0x265) =
3618 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003620 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003621 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 else
Felix Held04be2dd2018-07-29 04:53:22 +02003623 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624}
3625
3626static void restore_274265(struct raminfo *info)
3627{
3628 int channel;
3629
3630 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003631 MCHBAR32((channel << 10) + 0x274) =
3632 (info->cached_training->reg274265[channel][0] << 16) |
3633 info->cached_training->reg274265[channel][1];
3634 MCHBAR16((channel << 10) + 0x265) =
3635 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003637 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003638 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639 else
Felix Held04be2dd2018-07-29 04:53:22 +02003640 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003641}
3642
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643static void dmi_setup(void)
3644{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003645 gav(read8(DEFAULT_DMIBAR + 0x254));
3646 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3647 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003648 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003650 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003651
3652 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3653 DEFAULT_GPIOBASE | 0x38);
3654 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3655}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003657void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003658{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003660 u16 ggc;
3661 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662
Felix Held04be2dd2018-07-29 04:53:22 +02003663 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3665 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003666 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003667 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668 }
Felix Held29a9c072018-07-29 01:34:45 +02003669#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670 if (!s3resume) {
3671 pre_raminit_3(x2ca8);
3672 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003673 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674#endif
3675
3676 dmi_setup();
3677
Felix Held04be2dd2018-07-29 04:53:22 +02003678 MCHBAR16(0x1170) = 0xa880;
3679 MCHBAR8(0x11c1) = 0x1;
3680 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003681 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003683 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3684 /* 0 for 32MB */
3685 gfxsize = 0;
3686 }
3687
3688 ggc = 0xb00 | ((gfxsize + 5) << 4);
3689
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003690 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691
3692 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003693 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003694
3695 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003696 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003697 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003698 MCHBAR16_OR(0x2c30, 0x200);
3699 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003700 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003701 pci_read_config8(GMA, 0x62); // = 0x2
3702 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003703 read8(DEFAULT_RCBA + 0x2318);
3704 write8(DEFAULT_RCBA + 0x2318, 0x47);
3705 read8(DEFAULT_RCBA + 0x2320);
3706 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003707 }
3708
Felix Heldf83d80b2018-07-29 05:30:30 +02003709 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003711 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003712 gav(read32(DEFAULT_RCBA + 0x3428));
3713 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003714}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003716void raminit(const int s3resume, const u8 *spd_addrmap)
3717{
3718 unsigned channel, slot, lane, rank;
3719 int i;
3720 struct raminfo info;
3721 u8 x2ca8;
3722 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003723 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003724
Felix Heldf83d80b2018-07-29 05:30:30 +02003725 /* only used for dummy reads */
3726 volatile u8 tmp8;
3727 volatile u16 tmp16;
3728 volatile u32 tmp32;
3729
Felix Held04be2dd2018-07-29 04:53:22 +02003730 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003731 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003732
3733 memset(&info, 0x5a, sizeof(info));
3734
3735 info.last_500_command[0] = 0;
3736 info.last_500_command[1] = 0;
3737
3738 info.fsb_frequency = 135 * 2;
3739 info.board_lane_delay[0] = 0x14;
3740 info.board_lane_delay[1] = 0x07;
3741 info.board_lane_delay[2] = 0x07;
3742 info.board_lane_delay[3] = 0x08;
3743 info.board_lane_delay[4] = 0x56;
3744 info.board_lane_delay[5] = 0x04;
3745 info.board_lane_delay[6] = 0x04;
3746 info.board_lane_delay[7] = 0x05;
3747 info.board_lane_delay[8] = 0x10;
3748
3749 info.training.reg_178 = 0;
3750 info.training.reg_10b = 0;
3751
3752 info.heci_bar = 0;
3753 info.memory_reserved_for_heci_mb = 0;
3754
3755 /* before SPD */
3756 timestamp_add_now(101);
3757
Felix Held29a9c072018-07-29 01:34:45 +02003758 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003759 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003760
3761 collect_system_info(&info);
3762
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763 /* Enable SMBUS. */
3764 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765
3766 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3767
3768 info.use_ecc = 1;
3769 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003770 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771 int v;
3772 int try;
3773 int addr;
3774 const u8 useful_addresses[] = {
3775 DEVICE_TYPE,
3776 MODULE_TYPE,
3777 DENSITY,
3778 RANKS_AND_DQ,
3779 MEMORY_BUS_WIDTH,
3780 TIMEBASE_DIVIDEND,
3781 TIMEBASE_DIVISOR,
3782 CYCLETIME,
3783 CAS_LATENCIES_LSB,
3784 CAS_LATENCIES_MSB,
3785 CAS_LATENCY_TIME,
3786 0x11, 0x12, 0x13, 0x14, 0x15,
3787 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3788 0x1c, 0x1d,
3789 THERMAL_AND_REFRESH,
3790 0x20,
3791 REFERENCE_RAW_CARD_USED,
3792 RANK1_ADDRESS_MAPPING,
3793 0x75, 0x76, 0x77, 0x78,
3794 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3795 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3796 0x85, 0x86, 0x87, 0x88,
3797 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3798 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3799 0x95
3800 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003801 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003802 continue;
3803 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003804 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003805 DEVICE_TYPE);
3806 if (v >= 0)
3807 break;
3808 }
3809 if (v < 0)
3810 continue;
3811 for (addr = 0;
3812 addr <
3813 sizeof(useful_addresses) /
3814 sizeof(useful_addresses[0]); addr++)
3815 gav(info.
3816 spd[channel][0][useful_addresses
3817 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003818 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819 useful_addresses
3820 [addr]));
3821 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3822 die("Only DDR3 is supported");
3823
3824 v = info.spd[channel][0][RANKS_AND_DQ];
3825 info.populated_ranks[channel][0][0] = 1;
3826 info.populated_ranks[channel][0][1] =
3827 ((v >> 3) & 7);
3828 if (((v >> 3) & 7) > 1)
3829 die("At most 2 ranks are supported");
3830 if ((v & 7) == 0 || (v & 7) > 2)
3831 die("Only x8 and x16 modules are supported");
3832 if ((info.
3833 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3834 && (info.
3835 spd[channel][slot][MODULE_TYPE] & 0xF)
3836 != 3)
3837 die("Registered memory is not supported");
3838 info.is_x16_module[channel][0] = (v & 7) - 1;
3839 info.density[channel][slot] =
3840 info.spd[channel][slot][DENSITY] & 0xF;
3841 if (!
3842 (info.
3843 spd[channel][slot][MEMORY_BUS_WIDTH] &
3844 0x18))
3845 info.use_ecc = 0;
3846 }
3847
3848 gav(0x55);
3849
3850 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3851 int v = 0;
3852 for (slot = 0; slot < NUM_SLOTS; slot++)
3853 for (rank = 0; rank < NUM_RANKS; rank++)
3854 v |= info.
3855 populated_ranks[channel][slot][rank]
3856 << (2 * slot + rank);
3857 info.populated_ranks_mask[channel] = v;
3858 }
3859
3860 gav(0x55);
3861
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003862 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863 }
3864
3865 /* after SPD */
3866 timestamp_add_now(102);
3867
Felix Held04be2dd2018-07-29 04:53:22 +02003868 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869
3870 collect_system_info(&info);
3871 calculate_timings(&info);
3872
Felix Held29a9c072018-07-29 01:34:45 +02003873#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003874 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875#endif
3876
3877 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003878 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879 if (x2ca8 == 0 && (reg8 & 0x80)) {
3880 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3881 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3882 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3883 */
3884
3885 /* Clear bit7. */
3886
3887 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3888 (reg8 & ~(1 << 7)));
3889
3890 printk(BIOS_INFO,
3891 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003892 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893 }
3894 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895
3896 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003897 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3898 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003899
3900 compute_derived_timings(&info);
3901
3902 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003903 gav(MCHBAR8(0x164));
3904 MCHBAR8(0x164) = 0x26;
3905 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906 }
3907
Felix Held04be2dd2018-07-29 04:53:22 +02003908 MCHBAR32_OR(0x18b4, 0x210000);
3909 MCHBAR32_OR(0x1890, 0x2000000);
3910 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003912 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3913 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003914
Felix Held04be2dd2018-07-29 04:53:22 +02003915 gav(MCHBAR16(0x2c10));
3916 MCHBAR16(0x2c10) = 0x412;
3917 gav(MCHBAR16(0x2c10));
3918 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
Felix Held04be2dd2018-07-29 04:53:22 +02003920 gav(MCHBAR8(0x2ca8)); // !!!!
3921 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003923 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3924 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003925 gav(MCHBAR32(0x1c04)); // !!!!
3926 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
3928 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003929 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930 }
3931
Felix Held04be2dd2018-07-29 04:53:22 +02003932 MCHBAR32(0x18d8) = 0x120000;
3933 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003934 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3935 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003936 MCHBAR32(0x18d8) = 0x40000;
3937 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003938 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003940 MCHBAR32(0x18d8) = 0x180000;
3941 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003942 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3943 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003944 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945
Felix Held04be2dd2018-07-29 04:53:22 +02003946 gav(MCHBAR32(0x18dc)); // !!!!
3947 MCHBAR32(0x18dc) = 0x3;
3948 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003949
3950 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952 }
3953
Felix Held04be2dd2018-07-29 04:53:22 +02003954 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003955 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003956 MCHBAR32(0x1a10) = 0x4200010e;
3957 MCHBAR32_OR(0x18b8, 0x200);
3958 gav(MCHBAR32(0x1918)); // !!!!
3959 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003960
Felix Held04be2dd2018-07-29 04:53:22 +02003961 gav(MCHBAR32(0x18b8)); // !!!!
3962 MCHBAR32(0x18b8) = 0xe00;
3963 gav(MCHBAR32(0x182c)); // !!!!
3964 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003965 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3966 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003967 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3968 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003969
Felix Held04be2dd2018-07-29 04:53:22 +02003970 MCHBAR32_AND(0x18b4, 0xffff7fff);
3971 gav(MCHBAR32(0x1a68)); // !!!!
3972 MCHBAR32(0x1a68) = 0x343800;
3973 gav(MCHBAR32(0x1e68)); // !!!!
3974 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975
3976 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003977 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003978 }
3979
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003980 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3981 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3982 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3983 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3984 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3985 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3986 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003987 gav(MCHBAR32(0x1af0)); // !!!!
3988 gav(MCHBAR32(0x1af0)); // !!!!
3989 MCHBAR32(0x1af0) = 0x1f020003;
3990 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003991
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003992 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003993 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003994 }
3995
Felix Held04be2dd2018-07-29 04:53:22 +02003996 gav(MCHBAR32(0x1890)); // !!!!
3997 MCHBAR32(0x1890) = 0x80102;
3998 gav(MCHBAR32(0x18b4)); // !!!!
3999 MCHBAR32(0x18b4) = 0x216000;
4000 MCHBAR32(0x18a4) = 0x22222222;
4001 MCHBAR32(0x18a8) = 0x22222222;
4002 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004003
4004 udelay(1000);
4005
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004006 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004007
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004008 if (x2ca8 == 0) {
4009 int j;
4010 if (s3resume && info.cached_training) {
4011 restore_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004012 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004013 info.cached_training->reg2ca9_bit0);
4014 for (i = 0; i < 2; i++)
4015 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004016 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004017 i, j, info.cached_training->reg274265[i][j]);
4018 } else {
4019 set_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004020 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004021 info.training.reg2ca9_bit0);
4022 for (i = 0; i < 2; i++)
4023 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004024 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004025 i, j, info.training.reg274265[i][j]);
4026 }
4027
4028 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004029
4030 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004031 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004032 }
4033
4034 udelay(1000);
4035
4036 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004037 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004038 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004039 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4040 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4041 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004042
Felix Heldf83d80b2018-07-29 05:30:30 +02004043 tmp8 = MCHBAR8(0x1150);
4044 tmp8 = MCHBAR8(0x1151);
4045 tmp8 = MCHBAR8(0x1022);
4046 tmp8 = MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004047 MCHBAR32(0x1300) = 0x60606060;
4048 MCHBAR32(0x1304) = 0x60606060;
4049 MCHBAR32(0x1308) = 0x78797a7b;
4050 MCHBAR32(0x130c) = 0x7c7d7e7f;
4051 MCHBAR32(0x1310) = 0x60606060;
4052 MCHBAR32(0x1314) = 0x60606060;
4053 MCHBAR32(0x1318) = 0x60606060;
4054 MCHBAR32(0x131c) = 0x60606060;
4055 MCHBAR32(0x1320) = 0x50515253;
4056 MCHBAR32(0x1324) = 0x54555657;
4057 MCHBAR32(0x1328) = 0x58595a5b;
4058 MCHBAR32(0x132c) = 0x5c5d5e5f;
4059 MCHBAR32(0x1330) = 0x40414243;
4060 MCHBAR32(0x1334) = 0x44454647;
4061 MCHBAR32(0x1338) = 0x48494a4b;
4062 MCHBAR32(0x133c) = 0x4c4d4e4f;
4063 MCHBAR32(0x1340) = 0x30313233;
4064 MCHBAR32(0x1344) = 0x34353637;
4065 MCHBAR32(0x1348) = 0x38393a3b;
4066 MCHBAR32(0x134c) = 0x3c3d3e3f;
4067 MCHBAR32(0x1350) = 0x20212223;
4068 MCHBAR32(0x1354) = 0x24252627;
4069 MCHBAR32(0x1358) = 0x28292a2b;
4070 MCHBAR32(0x135c) = 0x2c2d2e2f;
4071 MCHBAR32(0x1360) = 0x10111213;
4072 MCHBAR32(0x1364) = 0x14151617;
4073 MCHBAR32(0x1368) = 0x18191a1b;
4074 MCHBAR32(0x136c) = 0x1c1d1e1f;
4075 MCHBAR32(0x1370) = 0x10203;
4076 MCHBAR32(0x1374) = 0x4050607;
4077 MCHBAR32(0x1378) = 0x8090a0b;
4078 MCHBAR32(0x137c) = 0xc0d0e0f;
4079 MCHBAR8(0x11cc) = 0x4e;
4080 MCHBAR32(0x1110) = 0x73970404;
4081 MCHBAR32(0x1114) = 0x72960404;
4082 MCHBAR32(0x1118) = 0x6f950404;
4083 MCHBAR32(0x111c) = 0x6d940404;
4084 MCHBAR32(0x1120) = 0x6a930404;
4085 MCHBAR32(0x1124) = 0x68a41404;
4086 MCHBAR32(0x1128) = 0x66a21404;
4087 MCHBAR32(0x112c) = 0x63a01404;
4088 MCHBAR32(0x1130) = 0x609e1404;
4089 MCHBAR32(0x1134) = 0x5f9c1404;
4090 MCHBAR32(0x1138) = 0x5c961404;
4091 MCHBAR32(0x113c) = 0x58a02404;
4092 MCHBAR32(0x1140) = 0x54942404;
4093 MCHBAR32(0x1190) = 0x900080a;
4094 MCHBAR16(0x11c0) = 0xc40b;
4095 MCHBAR16(0x11c2) = 0x303;
4096 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004097 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004098 MCHBAR32(0x11b8) = 0x70c3000;
4099 MCHBAR8(0x11ec) = 0xa;
4100 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004101 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004102 MCHBAR16(0x11ca) = 0xfa;
4103 MCHBAR32(0x11e4) = 0x4e20;
4104 MCHBAR8(0x11bc) = 0xf;
4105 MCHBAR16(0x11da) = 0x19;
4106 MCHBAR16(0x11ba) = 0x470c;
4107 MCHBAR32(0x1680) = 0xe6ffe4ff;
4108 MCHBAR32(0x1684) = 0xdeffdaff;
4109 MCHBAR32(0x1688) = 0xd4ffd0ff;
4110 MCHBAR32(0x168c) = 0xccffc6ff;
4111 MCHBAR32(0x1690) = 0xc0ffbeff;
4112 MCHBAR32(0x1694) = 0xb8ffb0ff;
4113 MCHBAR32(0x1698) = 0xa8ff0000;
4114 MCHBAR32(0x169c) = 0xc00;
4115 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004116 }
4117
Felix Held04be2dd2018-07-29 04:53:22 +02004118 MCHBAR32(0x124c) = 0x15040d00;
4119 MCHBAR32(0x1250) = 0x7f0000;
4120 MCHBAR32(0x1254) = 0x1e220004;
4121 MCHBAR32(0x1258) = 0x4000004;
4122 MCHBAR32(0x1278) = 0x0;
4123 MCHBAR32(0x125c) = 0x0;
4124 MCHBAR32(0x1260) = 0x0;
4125 MCHBAR32(0x1264) = 0x0;
4126 MCHBAR32(0x1268) = 0x0;
4127 MCHBAR32(0x126c) = 0x0;
4128 MCHBAR32(0x1270) = 0x0;
4129 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004130 }
4131
4132 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004133 MCHBAR16(0x1214) = 0x320;
4134 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004135 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4136 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004137 MCHBAR32(0x1400) = 0x13040020;
4138 MCHBAR32(0x1404) = 0xe090120;
4139 MCHBAR32(0x1408) = 0x5120220;
4140 MCHBAR32(0x140c) = 0x5120330;
4141 MCHBAR32(0x1410) = 0xe090220;
4142 MCHBAR32(0x1414) = 0x1010001;
4143 MCHBAR32(0x1418) = 0x1110000;
4144 MCHBAR32(0x141c) = 0x9020020;
4145 MCHBAR32(0x1420) = 0xd090220;
4146 MCHBAR32(0x1424) = 0x2090220;
4147 MCHBAR32(0x1428) = 0x2090330;
4148 MCHBAR32(0x142c) = 0xd090220;
4149 MCHBAR32(0x1430) = 0x1010001;
4150 MCHBAR32(0x1434) = 0x1110000;
4151 MCHBAR32(0x1438) = 0x11040020;
4152 MCHBAR32(0x143c) = 0x4030220;
4153 MCHBAR32(0x1440) = 0x1060220;
4154 MCHBAR32(0x1444) = 0x1060330;
4155 MCHBAR32(0x1448) = 0x4030220;
4156 MCHBAR32(0x144c) = 0x1010001;
4157 MCHBAR32(0x1450) = 0x1110000;
4158 MCHBAR32(0x1454) = 0x4010020;
4159 MCHBAR32(0x1458) = 0xb090220;
4160 MCHBAR32(0x145c) = 0x1090220;
4161 MCHBAR32(0x1460) = 0x1090330;
4162 MCHBAR32(0x1464) = 0xb090220;
4163 MCHBAR32(0x1468) = 0x1010001;
4164 MCHBAR32(0x146c) = 0x1110000;
4165 MCHBAR32(0x1470) = 0xf040020;
4166 MCHBAR32(0x1474) = 0xa090220;
4167 MCHBAR32(0x1478) = 0x1120220;
4168 MCHBAR32(0x147c) = 0x1120330;
4169 MCHBAR32(0x1480) = 0xa090220;
4170 MCHBAR32(0x1484) = 0x1010001;
4171 MCHBAR32(0x1488) = 0x1110000;
4172 MCHBAR32(0x148c) = 0x7020020;
4173 MCHBAR32(0x1490) = 0x1010220;
4174 MCHBAR32(0x1494) = 0x10210;
4175 MCHBAR32(0x1498) = 0x10320;
4176 MCHBAR32(0x149c) = 0x1010220;
4177 MCHBAR32(0x14a0) = 0x1010001;
4178 MCHBAR32(0x14a4) = 0x1110000;
4179 MCHBAR32(0x14a8) = 0xd040020;
4180 MCHBAR32(0x14ac) = 0x8090220;
4181 MCHBAR32(0x14b0) = 0x1111310;
4182 MCHBAR32(0x14b4) = 0x1111420;
4183 MCHBAR32(0x14b8) = 0x8090220;
4184 MCHBAR32(0x14bc) = 0x1010001;
4185 MCHBAR32(0x14c0) = 0x1110000;
4186 MCHBAR32(0x14c4) = 0x3010020;
4187 MCHBAR32(0x14c8) = 0x7090220;
4188 MCHBAR32(0x14cc) = 0x1081310;
4189 MCHBAR32(0x14d0) = 0x1081420;
4190 MCHBAR32(0x14d4) = 0x7090220;
4191 MCHBAR32(0x14d8) = 0x1010001;
4192 MCHBAR32(0x14dc) = 0x1110000;
4193 MCHBAR32(0x14e0) = 0xb040020;
4194 MCHBAR32(0x14e4) = 0x2030220;
4195 MCHBAR32(0x14e8) = 0x1051310;
4196 MCHBAR32(0x14ec) = 0x1051420;
4197 MCHBAR32(0x14f0) = 0x2030220;
4198 MCHBAR32(0x14f4) = 0x1010001;
4199 MCHBAR32(0x14f8) = 0x1110000;
4200 MCHBAR32(0x14fc) = 0x5020020;
4201 MCHBAR32(0x1500) = 0x5090220;
4202 MCHBAR32(0x1504) = 0x2071310;
4203 MCHBAR32(0x1508) = 0x2071420;
4204 MCHBAR32(0x150c) = 0x5090220;
4205 MCHBAR32(0x1510) = 0x1010001;
4206 MCHBAR32(0x1514) = 0x1110000;
4207 MCHBAR32(0x1518) = 0x7040120;
4208 MCHBAR32(0x151c) = 0x2090220;
4209 MCHBAR32(0x1520) = 0x70b1210;
4210 MCHBAR32(0x1524) = 0x70b1310;
4211 MCHBAR32(0x1528) = 0x2090220;
4212 MCHBAR32(0x152c) = 0x1010001;
4213 MCHBAR32(0x1530) = 0x1110000;
4214 MCHBAR32(0x1534) = 0x1010110;
4215 MCHBAR32(0x1538) = 0x1081310;
4216 MCHBAR32(0x153c) = 0x5041200;
4217 MCHBAR32(0x1540) = 0x5041310;
4218 MCHBAR32(0x1544) = 0x1081310;
4219 MCHBAR32(0x1548) = 0x1010001;
4220 MCHBAR32(0x154c) = 0x1110000;
4221 MCHBAR32(0x1550) = 0x1040120;
4222 MCHBAR32(0x1554) = 0x4051210;
4223 MCHBAR32(0x1558) = 0xd051200;
4224 MCHBAR32(0x155c) = 0xd051200;
4225 MCHBAR32(0x1560) = 0x4051210;
4226 MCHBAR32(0x1564) = 0x1010001;
4227 MCHBAR32(0x1568) = 0x1110000;
4228 MCHBAR16(0x1222) = 0x220a;
4229 MCHBAR16(0x123c) = 0x1fc0;
4230 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004231 }
4232
Felix Heldf83d80b2018-07-29 05:30:30 +02004233 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
4234 tmp32 = MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004235 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236
Felix Heldf83d80b2018-07-29 05:30:30 +02004237 tmp8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004238
4239 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004240 MCHBAR8_AND(0x2ca8, ~3);
4241 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4242 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004243 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004244 }
4245
Felix Held04be2dd2018-07-29 04:53:22 +02004246 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004247 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004248 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Felix Heldf83d80b2018-07-29 05:30:30 +02004249 tmp16 = MCHBAR16(0x2c20); // !!!!
4250 tmp16 = MCHBAR16(0x2c10); // !!!!
4251 tmp16 = MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004252 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253 udelay(1000);
4254 write_1d0(0, 0x33d, 0, 0);
4255 write_500(&info, 0, 0, 0xb61, 0, 0);
4256 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR32(0x1a30) = 0x0;
4258 MCHBAR32(0x1a34) = 0x0;
4259 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4260 (info.populated_ranks[0][0][0] * 0xa0);
4261 MCHBAR16(0x616) = 0x26a;
4262 MCHBAR32(0x134) = 0x856000;
4263 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004264 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4265 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004266 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004267 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4268 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004269 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004271 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4272 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004273 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4274 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4275 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4276 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4277 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4278 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4279 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4280 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4281 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4282 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004283 }
4284
4285 write_1d0(0x4, 0x151, 4, 1);
4286 write_1d0(0, 0x142, 3, 1);
4287 rdmsr(0x1ac); // !!!!
4288 write_500(&info, 1, 1, 0x6b3, 4, 1);
4289 write_500(&info, 1, 1, 0x6cf, 4, 1);
4290
4291 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4292
4293 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4294 populated_ranks[0]
4295 [0][0]) << 0),
4296 0x1d1, 3, 1);
4297 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004298 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4299 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004300 }
4301
4302 set_334(0);
4303
4304 program_base_timings(&info);
4305
Felix Held04be2dd2018-07-29 04:53:22 +02004306 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004307
4308 write_1d0(0x2, 0x1d5, 2, 1);
4309 write_1d0(0x20, 0x166, 7, 1);
4310 write_1d0(0x0, 0xeb, 3, 1);
4311 write_1d0(0x0, 0xf3, 6, 1);
4312
4313 for (channel = 0; channel < NUM_CHANNELS; channel++)
4314 for (lane = 0; lane < 9; lane++) {
4315 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4316 u8 a;
4317 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4318 write_500(&info, channel, a, addr, 6, 1);
4319 }
4320
4321 udelay(1000);
4322
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323 if (s3resume) {
4324 if (info.cached_training == NULL) {
4325 u32 reg32;
4326 printk(BIOS_ERR,
4327 "Couldn't find training data. Rebooting\n");
4328 reg32 = inl(DEFAULT_PMBASE + 0x04);
4329 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004330 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004331 }
4332 int tm;
4333 info.training = *info.cached_training;
4334 for (tm = 0; tm < 4; tm++)
4335 for (channel = 0; channel < NUM_CHANNELS; channel++)
4336 for (slot = 0; slot < NUM_SLOTS; slot++)
4337 for (rank = 0; rank < NUM_RANKS; rank++)
4338 for (lane = 0; lane < 9; lane++)
4339 write_500(&info,
4340 channel,
4341 info.training.
4342 lane_timings
4343 [tm][channel]
4344 [slot][rank]
4345 [lane],
4346 get_timing_register_addr
4347 (lane, tm,
4348 slot, rank),
4349 9, 0);
4350 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4351 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4352 }
4353
Felix Heldf83d80b2018-07-29 05:30:30 +02004354 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004355 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004356 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
4357 tmp8 = MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004358
4359 program_board_delay(&info);
4360
Felix Held04be2dd2018-07-29 04:53:22 +02004361 MCHBAR8(0x5ff) = 0x0;
4362 MCHBAR8(0x5ff) = 0x80;
4363 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004364
Felix Held04be2dd2018-07-29 04:53:22 +02004365 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004366 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004367 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004368 gav(read_1d0(0x14b, 7)); // = 0x81023100
4369 write_1d0(0x30, 0x14b, 7, 1);
4370 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4371 write_1d0(7, 0xd6, 6, 1);
4372 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4373 write_1d0(7, 0x328, 6, 1);
4374
4375 for (channel = 0; channel < NUM_CHANNELS; channel++)
4376 set_4cf(&info, channel,
4377 info.populated_ranks[channel][0][0] ? 8 : 0);
4378
4379 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4380 write_1d0(2, 0x116, 4, 1);
4381 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4382 write_1d0(0, 0xae, 6, 1);
4383 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4384 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004385 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4386 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004387 MCHBAR32_AND(0x140, ~0x07000000);
4388 MCHBAR32_AND(0x138, ~0x07000000);
4389 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004390 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004391 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004392 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004393
4394 {
4395 u32 t;
4396 u8 val_a1;
4397 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4398 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4399 rmw_1d0(0x320, 0x07,
4400 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4401 rmw_1d0(0x14b, 0x78,
4402 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4403 4), 7,
4404 1);
4405 rmw_1d0(0xce, 0x38,
4406 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4407 4), 6,
4408 1);
4409 }
4410
4411 for (channel = 0; channel < NUM_CHANNELS; channel++)
4412 set_4cf(&info, channel,
4413 info.populated_ranks[channel][0][0] ? 9 : 1);
4414
4415 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Felix Heldf83d80b2018-07-29 05:30:30 +02004416 tmp32 = MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004417 write_1d0(2, 0xae, 6, 1);
4418 write_1d0(2, 0x300, 6, 1);
4419 write_1d0(2, 0x121, 3, 1);
4420 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4421 write_1d0(4, 0xd6, 6, 1);
4422 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4423 write_1d0(4, 0x328, 6, 1);
4424
4425 for (channel = 0; channel < NUM_CHANNELS; channel++)
4426 set_4cf(&info, channel,
4427 info.populated_ranks[channel][0][0] ? 9 : 0);
4428
Felix Held04be2dd2018-07-29 04:53:22 +02004429 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4430 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004431 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004432 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004433 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4434 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4435 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4436 write_1d0(0, 0x21c, 6, 1);
4437 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4438 write_1d0(0x35, 0x14b, 7, 1);
4439
4440 for (channel = 0; channel < NUM_CHANNELS; channel++)
4441 set_4cf(&info, channel,
4442 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4443
4444 set_334(1);
4445
Felix Held04be2dd2018-07-29 04:53:22 +02004446 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004447
4448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4449 write_500(&info, channel,
4450 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4451 1);
4452 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4453 }
Felix Held04be2dd2018-07-29 04:53:22 +02004454 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4455 MCHBAR16(0x6c0) = 0x14a0;
4456 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4457 MCHBAR16(0x232) = 0x8;
4458 /* 0x40004 or 0 depending on ? */
4459 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4460 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4461 MCHBAR32(0x128) = 0x2150d05;
4462 MCHBAR8(0x12c) = 0x1f;
4463 MCHBAR8(0x12d) = 0x56;
4464 MCHBAR8(0x12e) = 0x31;
4465 MCHBAR8(0x12f) = 0x0;
4466 MCHBAR8(0x271) = 0x2;
4467 MCHBAR8(0x671) = 0x2;
4468 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004469 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004470 MCHBAR32(0x294 + (channel << 10)) =
4471 (info.populated_ranks_mask[channel] & 3) << 16;
4472 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4473 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004474 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004475 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4476 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004477
4478 if (!s3resume)
4479 jedec_init(&info);
4480
4481 int totalrank = 0;
4482 for (channel = 0; channel < NUM_CHANNELS; channel++)
4483 for (slot = 0; slot < NUM_SLOTS; slot++)
4484 for (rank = 0; rank < NUM_RANKS; rank++)
4485 if (info.populated_ranks[channel][slot][rank]) {
4486 jedec_read(&info, channel, slot, rank,
4487 totalrank, 0xa, 0x400);
4488 totalrank++;
4489 }
4490
Felix Held04be2dd2018-07-29 04:53:22 +02004491 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492
Felix Heldf83d80b2018-07-29 05:30:30 +02004493 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4494 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495
4496 if (!s3resume) {
4497 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR32(0x294 + (channel << 10)) =
4499 (info.populated_ranks_mask[channel] & 3) << 16;
4500 MCHBAR16(0x298 + (channel << 10)) =
4501 info.populated_ranks[channel][0][0] |
4502 (info.populated_ranks[channel][0][1] << 5);
4503 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004505 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506
4507 {
4508 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004509 a = MCHBAR8(0x243);
4510 b = MCHBAR8(0x643);
4511 MCHBAR8(0x243) = a | 2;
4512 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 }
4514
4515 write_1d0(7, 0x19b, 3, 1);
4516 write_1d0(7, 0x1c0, 3, 1);
4517 write_1d0(4, 0x1c6, 4, 1);
4518 write_1d0(4, 0x1cc, 4, 1);
4519 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4520 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004521 MCHBAR32(0x584) = 0xfffff;
4522 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523
4524 for (channel = 0; channel < NUM_CHANNELS; channel++)
4525 for (slot = 0; slot < NUM_SLOTS; slot++)
4526 for (rank = 0; rank < NUM_RANKS; rank++)
4527 if (info.
4528 populated_ranks[channel][slot]
4529 [rank])
4530 config_rank(&info, s3resume,
4531 channel, slot,
4532 rank);
4533
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR8(0x243) = 0x1;
4535 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004536 }
4537
4538 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004539 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540 write_26c(0, 0x820);
4541 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004542 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 /* end */
4544
4545 if (s3resume) {
4546 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR32(0x294 + (channel << 10)) =
4548 (info.populated_ranks_mask[channel] & 3) << 16;
4549 MCHBAR16(0x298 + (channel << 10)) =
4550 info.populated_ranks[channel][0][0] |
4551 (info.populated_ranks[channel][0][1] << 5);
4552 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004554 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004555 }
4556
Felix Held04be2dd2018-07-29 04:53:22 +02004557 MCHBAR32_AND(0xfa4, ~0x01000002);
4558 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 /* Before training. */
4561 timestamp_add_now(103);
4562
4563 if (!s3resume)
4564 ram_training(&info);
4565
4566 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004567 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568
4569 dump_timings(&info);
4570
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 program_modules_memory_map(&info, 0);
4572 program_total_memory_map(&info);
4573
4574 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 else
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR32_AND(0xfac, ~0x80000000);
4584 MCHBAR32(0xfb4) = 0x4800;
4585 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4586 MCHBAR32(0xe94) = 0x7ffff;
4587 MCHBAR32(0xfc0) = 0x80002040;
4588 MCHBAR32(0xfc4) = 0x701246;
4589 MCHBAR8_AND(0xfc8, ~0x70);
4590 MCHBAR32_OR(0xe5c, 0x1000000);
4591 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4592 MCHBAR32(0x50) = 0x700b0;
4593 MCHBAR32(0x3c) = 0x10;
4594 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4595 MCHBAR8_OR(0xff4, 0x2);
4596 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597
Felix Held29a9c072018-07-29 01:34:45 +02004598#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4600 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4601 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004602
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004603 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4604 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4605 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004606
4607#else
4608 {
4609 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004610 // = 0xe911714b
4611 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4612 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4613 // = 0xe911714b
4614 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4615 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004616 }
4617#endif
4618
4619 {
4620 u32 eax;
4621
4622 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004623 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4624 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4625 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626 }
4627
4628 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004631 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632 else
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636
Felix Held04be2dd2018-07-29 04:53:22 +02004637 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004639 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004640 else
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642 }
4643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
4646 {
4647 u8 al;
4648 al = 0xd;
4649 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4650 al += 2;
4651 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653 }
4654
4655 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4657 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4658 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4659 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004662 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004663 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004664 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004665 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Felix Heldf83d80b2018-07-29 05:30:30 +02004666 tmp8 = MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004667 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004668 MCHBAR8_OR(0x1210, 2);
4669 MCHBAR32(0x1200) = 0x8800440;
4670 MCHBAR32(0x1204) = 0x53ff0453;
4671 MCHBAR32(0x1208) = 0x19002043;
4672 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
4674 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR16(0x1214) = 0x220;
4676 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677 }
4678
Felix Held04be2dd2018-07-29 04:53:22 +02004679 MCHBAR8_OR(0x1214, 0x4);
4680 MCHBAR8(0x120c) = 0x1;
4681 MCHBAR8(0x1218) = 0x3;
4682 MCHBAR8(0x121a) = 0x3;
4683 MCHBAR8(0x121c) = 0x3;
4684 MCHBAR16(0xc14) = 0x0;
4685 MCHBAR16(0xc20) = 0x0;
4686 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004687
4688 /* revision dependent here. */
4689
Felix Held04be2dd2018-07-29 04:53:22 +02004690 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
4692 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
Felix Held04be2dd2018-07-29 04:53:22 +02004695 MCHBAR16_OR(0x1230, 0x8000);
4696 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697
4698 u8 bl, ebpb;
4699 u16 reg_1020;
4700
Felix Held04be2dd2018-07-29 04:53:22 +02004701 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4702 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
Felix Held04be2dd2018-07-29 04:53:22 +02004704 MCHBAR32(0x1000) = 0x100;
4705 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706
4707 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 bl = reg_1020 >> 8;
4710 ebpb = reg_1020 & 0xff;
4711 } else {
4712 ebpb = 0;
4713 bl = 8;
4714 }
4715
4716 rdmsr(0x1a2);
4717
Felix Held04be2dd2018-07-29 04:53:22 +02004718 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719
Felix Held04be2dd2018-07-29 04:53:22 +02004720 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004723
Felix Held04be2dd2018-07-29 04:53:22 +02004724 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004726 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4727 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004728 }
4729
4730 setup_heci_uma(&info);
4731
4732 if (info.uma_enabled) {
4733 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004734 MCHBAR32_OR(0x11b0, 0x4000);
4735 MCHBAR32_OR(0x11b4, 0x4000);
4736 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004737
Felix Held04be2dd2018-07-29 04:53:22 +02004738 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4739 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4740 MCHBAR16_OR(0x1170, 0x1000);
4741
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004742 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004743
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004745 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004746 ;
4747 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004748 }
4749
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004750 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4751 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004752 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004753 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755 udelay(1000);
4756 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004757 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4758
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004759 if (!s3resume)
4760 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004761 if (s3resume && cbmem_wasnot_inited) {
4762 u32 reg32;
4763 printk(BIOS_ERR, "Failed S3 resume.\n");
4764 ram_check(0x100000, 0x200000);
4765
4766 /* Clear SLP_TYPE. */
4767 reg32 = inl(DEFAULT_PMBASE + 0x04);
4768 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4769
4770 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004771 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004772 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004773}