blob: de02882483e3251e58e7121b0dc5b2cc0b9ec73f [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010017#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +010018#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010024#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010025#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020026#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020028#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010029#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020039#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010040#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020041#include <types.h>
42
43#include "chip.h"
44#include "nehalem.h"
45#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020046#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010047
48#define NORTHBRIDGE PCI_DEV(0, 0, 0)
49#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
50#define GMA PCI_DEV (0, 0x2, 0x0)
51#define HECIDEV PCI_DEV(0, 0x16, 0)
52#define HECIBAR 0x10
53
54#define FOR_ALL_RANKS \
55 for (channel = 0; channel < NUM_CHANNELS; channel++) \
56 for (slot = 0; slot < NUM_SLOTS; slot++) \
57 for (rank = 0; rank < NUM_RANKS; rank++)
58
59#define FOR_POPULATED_RANKS \
60 for (channel = 0; channel < NUM_CHANNELS; channel++) \
61 for (slot = 0; slot < NUM_SLOTS; slot++) \
62 for (rank = 0; rank < NUM_RANKS; rank++) \
63 if (info->populated_ranks[channel][slot][rank])
64
65#define FOR_POPULATED_RANKS_BACKWARDS \
66 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
67 for (slot = 0; slot < NUM_SLOTS; slot++) \
68 for (rank = 0; rank < NUM_RANKS; rank++) \
69 if (info->populated_ranks[channel][slot][rank])
70
71/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
72typedef struct {
73 u8 smallest;
74 u8 largest;
75} timing_bounds_t[2][2][2][9];
76
Arthur Heymansdc71e252018-01-29 10:14:48 +010077#define MRC_CACHE_VERSION 1
78
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010079struct ram_training {
80 /* [TM][CHANNEL][SLOT][RANK][LANE] */
81 u16 lane_timings[4][2][2][2][9];
82 u16 reg_178;
83 u16 reg_10b;
84
85 u8 reg178_center;
86 u8 reg178_smallest;
87 u8 reg178_largest;
88 timing_bounds_t timing_bounds[2];
89 u16 timing_offset[2][2][2][9];
90 u16 timing2_offset[2][2][2][9];
91 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010092 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
93 u8 reg2ca9_bit0;
94 u32 reg_6dc;
95 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096};
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098#include <lib.h> /* Prototypes */
99
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100100typedef struct _u128 {
101 u64 lo;
102 u64 hi;
103} u128;
104
105static void read128(u32 addr, u64 * out)
106{
107 u128 ret;
108 u128 stor;
109 asm volatile ("movdqu %%xmm0, %0\n"
110 "movdqa (%2), %%xmm0\n"
111 "movdqu %%xmm0, %1\n"
112 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
113 out[0] = ret.lo;
114 out[1] = ret.hi;
115}
116
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100117/* OK */
118static void write_1d0(u32 val, u16 addr, int bits, int flag)
119{
Felix Held04be2dd2018-07-29 04:53:22 +0200120 MCHBAR32(0x1d0) = 0;
121 while (MCHBAR32(0x1d0) & 0x800000)
122 ;
123 MCHBAR32(0x1d4) =
124 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
125 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200126 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200127 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100128}
129
130/* OK */
131static u16 read_1d0(u16 addr, int split)
132{
133 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200134 MCHBAR32(0x1d0) = 0;
135 while (MCHBAR32(0x1d0) & 0x800000)
136 ;
137 MCHBAR32(0x1d0) =
138 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
139 while (MCHBAR32(0x1d0) & 0x800000)
140 ;
141 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100142 write_1d0(0, 0x33d, 0, 0);
143 write_1d0(0, 0x33d, 0, 0);
144 val &= ((1 << split) - 1);
145 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
146 return val;
147}
148
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800149static void write32p(uintptr_t addr, uint32_t val)
150{
151 write32((void *)addr, val);
152}
153
154static uint32_t read32p(uintptr_t addr)
155{
156 return read32((void *)addr);
157}
158
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100159static void sfence(void)
160{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100161 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100162}
163
164static inline u16 get_lane_offset(int slot, int rank, int lane)
165{
166 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
167 0x452 * (lane == 8);
168}
169
170static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
171{
172 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
173 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
174}
175
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100176static u32 gav_real(int line, u32 in)
177{
178 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
179 return in;
180}
181
182#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200183
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100184struct raminfo {
185 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
186 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
187 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
188 u8 density[2][2]; /* [CHANNEL][SLOT] */
189 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
190 int rank_start[2][2][2];
191 u8 cas_latency;
192 u8 board_lane_delay[9];
193 u8 use_ecc;
194 u8 revision;
195 u8 max_supported_clock_speed_index;
196 u8 uma_enabled;
197 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
198 u8 silicon_revision;
199 u8 populated_ranks_mask[2];
200 u8 max_slots_used_in_channel;
201 u8 mode4030[2];
202 u16 avg4044[2];
203 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600204 unsigned int total_memory_mb;
205 unsigned int interleaved_part_mb;
206 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100207
208 u32 heci_bar;
209 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600210 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100211
212 struct ram_training training;
213 u32 last_500_command[2];
214
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100215 u32 delay46_ps[2];
216 u32 delay54_ps[2];
217 u8 revision_flag_1;
218 u8 some_delay_1_cycle_floor;
219 u8 some_delay_2_halfcycles_ceil;
220 u8 some_delay_3_ps_rounded;
221
222 const struct ram_training *cached_training;
223};
224
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200225/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100226timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200227
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100228static void
229write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
230 int flag);
231
232/* OK */
233static u16
234read_500(struct raminfo *info, int channel, u16 addr, int split)
235{
236 u32 val;
237 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200238 MCHBAR32(0x500 + (channel << 10)) = 0;
239 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
240 ;
241 MCHBAR32(0x500 + (channel << 10)) =
242 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
243 + 0xb88 - addr);
244 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
245 ;
246 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100247 return val & ((1 << split) - 1);
248}
249
250/* OK */
251static void
252write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
253 int flag)
254{
255 if (info->last_500_command[channel] == 0x80000000) {
256 info->last_500_command[channel] = 0x40000000;
257 write_500(info, channel, 0, 0xb61, 0, 0);
258 }
Felix Held04be2dd2018-07-29 04:53:22 +0200259 MCHBAR32(0x500 + (channel << 10)) = 0;
260 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
261 ;
262 MCHBAR32(0x504 + (channel << 10)) =
263 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
264 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200265 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200266 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100267}
268
269static int rw_test(int rank)
270{
271 const u32 mask = 0xf00fc33c;
272 int ok = 0xff;
273 int i;
274 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800275 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276 sfence();
277 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800278 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100279 sfence();
280 for (i = 0; i < 32; i++) {
281 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 write32p((rank << 28) | (i << 3), pat);
283 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100284 }
285 sfence();
286 for (i = 0; i < 32; i++) {
287 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
288 int j;
289 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800290 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291 for (j = 0; j < 4; j++)
292 if (((val >> (j * 8)) & 0xff) != pat)
293 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(16 << j);
298 }
299 sfence();
300 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800301 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100302 sfence();
303 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800304 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100305
306 return ok;
307}
308
309static void
310program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
311{
312 int lane;
313 for (lane = 0; lane < 8; lane++) {
314 write_500(info, channel,
315 base +
316 info->training.
317 lane_timings[2][channel][slot][rank][lane],
318 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
319 write_500(info, channel,
320 base +
321 info->training.
322 lane_timings[3][channel][slot][rank][lane],
323 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
324 }
325}
326
327static void write_26c(int channel, u16 si)
328{
Felix Held04be2dd2018-07-29 04:53:22 +0200329 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
330 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
331 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332}
333
334static u32 get_580(int channel, u8 addr)
335{
336 u32 ret;
337 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200338 MCHBAR8(0x5ff) = 0x0;
339 MCHBAR8(0x5ff) = 0x80;
340 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
341 MCHBAR8_OR(0x580 + (channel << 10), 1);
342 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
343 ;
344 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100345 return ret;
346}
347
348const int cached_config = 0;
349
350#define NUM_CHANNELS 2
351#define NUM_SLOTS 2
352#define NUM_RANKS 2
353#define RANK_SHIFT 28
354#define CHANNEL_SHIFT 10
355
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100356static void seq9(struct raminfo *info, int channel, int slot, int rank)
357{
358 int i, lane;
359
360 for (i = 0; i < 2; i++)
361 for (lane = 0; lane < 8; lane++)
362 write_500(info, channel,
363 info->training.lane_timings[i +
364 1][channel][slot]
365 [rank][lane], get_timing_register_addr(lane,
366 i + 1,
367 slot,
368 rank),
369 9, 0);
370
371 write_1d0(1, 0x103, 6, 1);
372 for (lane = 0; lane < 8; lane++)
373 write_500(info, channel,
374 info->training.
375 lane_timings[0][channel][slot][rank][lane],
376 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
377
378 for (i = 0; i < 2; i++) {
379 for (lane = 0; lane < 8; lane++)
380 write_500(info, channel,
381 info->training.lane_timings[i +
382 1][channel][slot]
383 [rank][lane], get_timing_register_addr(lane,
384 i + 1,
385 slot,
386 rank),
387 9, 0);
388 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
389 }
390
391 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200392 MCHBAR8(0x5ff) = 0x0;
393 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100394 write_1d0(0x2, 0x142, 3, 1);
395 for (lane = 0; lane < 8; lane++) {
396 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
397 info->training.lane_timings[2][channel][slot][rank][lane] =
398 read_500(info, channel,
399 get_timing_register_addr(lane, 2, slot, rank), 9);
400 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
401 info->training.lane_timings[3][channel][slot][rank][lane] =
402 info->training.lane_timings[2][channel][slot][rank][lane] +
403 0x20;
404 }
405}
406
407static int count_ranks_in_channel(struct raminfo *info, int channel)
408{
409 int slot, rank;
410 int res = 0;
411 for (slot = 0; slot < NUM_SLOTS; slot++)
412 for (rank = 0; rank < NUM_SLOTS; rank++)
413 res += info->populated_ranks[channel][slot][rank];
414 return res;
415}
416
417static void
418config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
419{
420 int add;
421
422 write_1d0(0, 0x178, 7, 1);
423 seq9(info, channel, slot, rank);
424 program_timings(info, 0x80, channel, slot, rank);
425
426 if (channel == 0)
427 add = count_ranks_in_channel(info, 1);
428 else
429 add = 0;
430 if (!s3resume)
431 gav(rw_test(rank + add));
432 program_timings(info, 0x00, channel, slot, rank);
433 if (!s3resume)
434 gav(rw_test(rank + add));
435 if (!s3resume)
436 gav(rw_test(rank + add));
437 write_1d0(0, 0x142, 3, 1);
438 write_1d0(0, 0x103, 6, 1);
439
440 gav(get_580(channel, 0xc | (rank << 5)));
441 gav(read_1d0(0x142, 3));
442
Felix Held04be2dd2018-07-29 04:53:22 +0200443 MCHBAR8(0x5ff) = 0x0;
444 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100445}
446
447static void set_4cf(struct raminfo *info, int channel, u8 val)
448{
449 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
450 write_500(info, channel, val, 0x4cf, 4, 1);
451 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
452 write_500(info, channel, val, 0x659, 4, 1);
453 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
454 write_500(info, channel, val, 0x697, 4, 1);
455}
456
457static void set_334(int zero)
458{
459 int j, k, channel;
460 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
461 u32 vd8[2][16];
462
463 for (channel = 0; channel < NUM_CHANNELS; channel++) {
464 for (j = 0; j < 4; j++) {
465 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
466 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
467 u16 c;
468 if ((j == 0 || j == 3) && zero)
469 c = 0;
470 else if (j == 3)
471 c = 0x5f;
472 else
473 c = 0x5f5f;
474
475 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200476 MCHBAR32(0x138 + 8 * k) =
477 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100478 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200479 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100480 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200481 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100482 }
483
Felix Held22ca8cb2018-07-29 05:09:44 +0200484 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
485 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200486 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
487 zero ? 0 : (0x18191819 & lmask);
488 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
489 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
490 zero ? 0 : (a & lmask);
491 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
492 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100493 }
494 }
495
Felix Held04be2dd2018-07-29 04:53:22 +0200496 MCHBAR32_OR(0x130, 1);
497 while (MCHBAR8(0x130) & 1)
498 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499}
500
501static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
502{
503 u32 v;
504 v = read_1d0(addr, split);
505 write_1d0((v & and) | or, addr, split, flag);
506}
507
508static int find_highest_bit_set(u16 val)
509{
510 int i;
511 for (i = 15; i >= 0; i--)
512 if (val & (1 << i))
513 return i;
514 return -1;
515}
516
517static int find_lowest_bit_set32(u32 val)
518{
519 int i;
520 for (i = 0; i < 32; i++)
521 if (val & (1 << i))
522 return i;
523 return -1;
524}
525
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100526enum {
527 DEVICE_TYPE = 2,
528 MODULE_TYPE = 3,
529 DENSITY = 4,
530 RANKS_AND_DQ = 7,
531 MEMORY_BUS_WIDTH = 8,
532 TIMEBASE_DIVIDEND = 10,
533 TIMEBASE_DIVISOR = 11,
534 CYCLETIME = 12,
535
536 CAS_LATENCIES_LSB = 14,
537 CAS_LATENCIES_MSB = 15,
538 CAS_LATENCY_TIME = 16,
539 THERMAL_AND_REFRESH = 31,
540 REFERENCE_RAW_CARD_USED = 62,
541 RANK1_ADDRESS_MAPPING = 63
542};
543
544static void calculate_timings(struct raminfo *info)
545{
Martin Roth468d02c2019-10-23 21:44:42 -0600546 unsigned int cycletime;
547 unsigned int cas_latency_time;
548 unsigned int supported_cas_latencies;
549 unsigned int channel, slot;
550 unsigned int clock_speed_index;
551 unsigned int min_cas_latency;
552 unsigned int cas_latency;
553 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100554
555 /* Find common CAS latency */
556 supported_cas_latencies = 0x3fe;
557 for (channel = 0; channel < NUM_CHANNELS; channel++)
558 for (slot = 0; slot < NUM_SLOTS; slot++)
559 if (info->populated_ranks[channel][slot][0])
560 supported_cas_latencies &=
561 2 *
562 (info->
563 spd[channel][slot][CAS_LATENCIES_LSB] |
564 (info->
565 spd[channel][slot][CAS_LATENCIES_MSB] <<
566 8));
567
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100568 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100569
570 cycletime = min_cycletime[max_clock_index];
571 cas_latency_time = min_cas_latency_time[max_clock_index];
572
573 for (channel = 0; channel < NUM_CHANNELS; channel++)
574 for (slot = 0; slot < NUM_SLOTS; slot++)
575 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600576 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100577 timebase =
578 1000 *
579 info->
580 spd[channel][slot][TIMEBASE_DIVIDEND] /
581 info->spd[channel][slot][TIMEBASE_DIVISOR];
582 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100583 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100584 timebase *
585 info->spd[channel][slot][CYCLETIME]);
586 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100587 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100588 timebase *
589 info->
590 spd[channel][slot][CAS_LATENCY_TIME]);
591 }
Jacob Garber3c193822019-06-10 18:23:32 -0600592 if (cycletime > min_cycletime[0])
593 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100594 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
595 if (cycletime == min_cycletime[clock_speed_index])
596 break;
597 if (cycletime > min_cycletime[clock_speed_index]) {
598 clock_speed_index--;
599 cycletime = min_cycletime[clock_speed_index];
600 break;
601 }
602 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100603 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100604 cas_latency = 0;
605 while (supported_cas_latencies) {
606 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
607 if (cas_latency <= min_cas_latency)
608 break;
609 supported_cas_latencies &=
610 ~(1 << find_highest_bit_set(supported_cas_latencies));
611 }
612
613 if (cas_latency != min_cas_latency && clock_speed_index)
614 clock_speed_index--;
615
616 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
617 die("Couldn't configure DRAM");
618 info->clock_speed_index = clock_speed_index;
619 info->cas_latency = cas_latency;
620}
621
622static void program_base_timings(struct raminfo *info)
623{
Martin Roth468d02c2019-10-23 21:44:42 -0600624 unsigned int channel;
625 unsigned int slot, rank, lane;
626 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100627 int i;
628
629 extended_silicon_revision = info->silicon_revision;
630 if (info->silicon_revision == 0)
631 for (channel = 0; channel < NUM_CHANNELS; channel++)
632 for (slot = 0; slot < NUM_SLOTS; slot++)
633 if ((info->
634 spd[channel][slot][MODULE_TYPE] & 0xF) ==
635 3)
636 extended_silicon_revision = 4;
637
638 for (channel = 0; channel < NUM_CHANNELS; channel++) {
639 for (slot = 0; slot < NUM_SLOTS; slot++)
640 for (rank = 0; rank < NUM_SLOTS; rank++) {
641 int card_timing_2;
642 if (!info->populated_ranks[channel][slot][rank])
643 continue;
644
645 for (lane = 0; lane < 9; lane++) {
646 int tm_reg;
647 int card_timing;
648
649 card_timing = 0;
650 if ((info->
651 spd[channel][slot][MODULE_TYPE] &
652 0xF) == 3) {
653 int reference_card;
654 reference_card =
655 info->
656 spd[channel][slot]
657 [REFERENCE_RAW_CARD_USED] &
658 0x1f;
659 if (reference_card == 3)
660 card_timing =
661 u16_ffd1188[0][lane]
662 [info->
663 clock_speed_index];
664 if (reference_card == 5)
665 card_timing =
666 u16_ffd1188[1][lane]
667 [info->
668 clock_speed_index];
669 }
670
671 info->training.
672 lane_timings[0][channel][slot][rank]
673 [lane] =
674 u8_FFFD1218[info->
675 clock_speed_index];
676 info->training.
677 lane_timings[1][channel][slot][rank]
678 [lane] = 256;
679
680 for (tm_reg = 2; tm_reg < 4; tm_reg++)
681 info->training.
682 lane_timings[tm_reg]
683 [channel][slot][rank][lane]
684 =
685 u8_FFFD1240[channel]
686 [extended_silicon_revision]
687 [lane][2 * slot +
688 rank][info->
689 clock_speed_index]
690 + info->max4048[channel]
691 +
692 u8_FFFD0C78[channel]
693 [extended_silicon_revision]
694 [info->
695 mode4030[channel]][slot]
696 [rank][info->
697 clock_speed_index]
698 + card_timing;
699 for (tm_reg = 0; tm_reg < 4; tm_reg++)
700 write_500(info, channel,
701 info->training.
702 lane_timings[tm_reg]
703 [channel][slot][rank]
704 [lane],
705 get_timing_register_addr
706 (lane, tm_reg, slot,
707 rank), 9, 0);
708 }
709
710 card_timing_2 = 0;
711 if (!(extended_silicon_revision != 4
712 || (info->
713 populated_ranks_mask[channel] & 5) ==
714 5)) {
715 if ((info->
716 spd[channel][slot]
717 [REFERENCE_RAW_CARD_USED] & 0x1F)
718 == 3)
719 card_timing_2 =
720 u16_FFFE0EB8[0][info->
721 clock_speed_index];
722 if ((info->
723 spd[channel][slot]
724 [REFERENCE_RAW_CARD_USED] & 0x1F)
725 == 5)
726 card_timing_2 =
727 u16_FFFE0EB8[1][info->
728 clock_speed_index];
729 }
730
731 for (i = 0; i < 3; i++)
732 write_500(info, channel,
733 (card_timing_2 +
734 info->max4048[channel]
735 +
736 u8_FFFD0EF8[channel]
737 [extended_silicon_revision]
738 [info->
739 mode4030[channel]][info->
740 clock_speed_index]),
741 u16_fffd0c50[i][slot][rank],
742 8, 1);
743 write_500(info, channel,
744 (info->max4048[channel] +
745 u8_FFFD0C78[channel]
746 [extended_silicon_revision][info->
747 mode4030
748 [channel]]
749 [slot][rank][info->
750 clock_speed_index]),
751 u16_fffd0c70[slot][rank], 7, 1);
752 }
753 if (!info->populated_ranks_mask[channel])
754 continue;
755 for (i = 0; i < 3; i++)
756 write_500(info, channel,
757 (info->max4048[channel] +
758 info->avg4044[channel]
759 +
760 u8_FFFD17E0[channel]
761 [extended_silicon_revision][info->
762 mode4030
763 [channel]][info->
764 clock_speed_index]),
765 u16_fffd0c68[i], 8, 1);
766 }
767}
768
769static unsigned int fsbcycle_ps(struct raminfo *info)
770{
771 return 900000 / info->fsb_frequency;
772}
773
774/* The time of DDR transfer in ps. */
775static unsigned int halfcycle_ps(struct raminfo *info)
776{
777 return 3750 / (info->clock_speed_index + 3);
778}
779
780/* The time of clock cycle in ps. */
781static unsigned int cycle_ps(struct raminfo *info)
782{
783 return 2 * halfcycle_ps(info);
784}
785
786/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600787static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100788{
789 return (info->clock_speed_index + 3) * 120;
790}
791
792/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600793static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100794{
795 return 100 * frequency_11(info) / 9;
796}
797
Martin Roth468d02c2019-10-23 21:44:42 -0600798static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100799{
800 return (frequency_11(info) * 2) * ps / 900000;
801}
802
Martin Roth468d02c2019-10-23 21:44:42 -0600803static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100804{
805 return (frequency_11(info)) * ns / 900;
806}
807
808static void compute_derived_timings(struct raminfo *info)
809{
Martin Roth468d02c2019-10-23 21:44:42 -0600810 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100811 int extended_silicon_revision;
812 int some_delay_1_ps;
813 int some_delay_2_ps;
814 int some_delay_2_halfcycles_ceil;
815 int some_delay_2_halfcycles_floor;
816 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100817 int some_delay_3_ps_rounded;
818 int some_delay_1_cycle_ceil;
819 int some_delay_1_cycle_floor;
820
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100821 some_delay_3_ps_rounded = 0;
822 extended_silicon_revision = info->silicon_revision;
823 if (!info->silicon_revision)
824 for (channel = 0; channel < NUM_CHANNELS; channel++)
825 for (slot = 0; slot < NUM_SLOTS; slot++)
826 if ((info->
827 spd[channel][slot][MODULE_TYPE] & 0xF) ==
828 3)
829 extended_silicon_revision = 4;
830 if (info->board_lane_delay[7] < 5)
831 info->board_lane_delay[7] = 5;
832 info->revision_flag_1 = 2;
833 if (info->silicon_revision == 2 || info->silicon_revision == 3)
834 info->revision_flag_1 = 0;
835 if (info->revision < 16)
836 info->revision_flag_1 = 0;
837
838 if (info->revision < 8)
839 info->revision_flag_1 = 0;
840 if (info->revision >= 8 && (info->silicon_revision == 0
841 || info->silicon_revision == 1))
842 some_delay_2_ps = 735;
843 else
844 some_delay_2_ps = 750;
845
846 if (info->revision >= 0x10 && (info->silicon_revision == 0
847 || info->silicon_revision == 1))
848 some_delay_1_ps = 3929;
849 else
850 some_delay_1_ps = 3490;
851
852 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
853 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
854 if (some_delay_1_ps % cycle_ps(info))
855 some_delay_1_cycle_ceil++;
856 else
857 some_delay_1_cycle_floor--;
858 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
859 if (info->revision_flag_1)
860 some_delay_2_ps = halfcycle_ps(info) >> 6;
861 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100862 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100863 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
864 375;
865 some_delay_3_ps =
866 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
867 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200868 if (some_delay_3_ps >= 150) {
869 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100870 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200871 some_delay_3_ps_rounded =
872 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
873 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100874 }
875 some_delay_2_halfcycles_ceil =
876 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
877 2 * (some_delay_1_cycle_ceil - 1);
878 if (info->revision_flag_1 && some_delay_3_ps < 150)
879 some_delay_2_halfcycles_ceil++;
880 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
881 if (info->revision < 0x10)
882 some_delay_2_halfcycles_floor =
883 some_delay_2_halfcycles_ceil - 1;
884 if (!info->revision_flag_1)
885 some_delay_2_halfcycles_floor++;
886 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
887 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
888 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
889 || (info->populated_ranks[1][0][0]
890 && info->populated_ranks[1][1][0]))
891 info->max_slots_used_in_channel = 2;
892 else
893 info->max_slots_used_in_channel = 1;
894 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200895 MCHBAR32(0x244 + (channel << 10)) =
896 ((info->revision < 8) ? 1 : 0x200) |
897 ((2 - info->max_slots_used_in_channel) << 17) |
898 (channel << 21) |
899 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100900 if (info->max_slots_used_in_channel == 1) {
901 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
902 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
903 } else {
904 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 */
905 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
906 || (count_ranks_in_channel(info, 1) ==
907 2)) ? 2 : 3;
908 }
909 for (channel = 0; channel < NUM_CHANNELS; channel++) {
910 int max_of_unk;
911 int min_of_unk_2;
912
913 int i, count;
914 int sum;
915
916 if (!info->populated_ranks_mask[channel])
917 continue;
918
919 max_of_unk = 0;
920 min_of_unk_2 = 32767;
921
922 sum = 0;
923 count = 0;
924 for (i = 0; i < 3; i++) {
925 int unk1;
926 if (info->revision < 8)
927 unk1 =
928 u8_FFFD1891[0][channel][info->
929 clock_speed_index]
930 [i];
931 else if (!
932 (info->revision >= 0x10
933 || info->revision_flag_1))
934 unk1 =
935 u8_FFFD1891[1][channel][info->
936 clock_speed_index]
937 [i];
938 else
939 unk1 = 0;
940 for (slot = 0; slot < NUM_SLOTS; slot++)
941 for (rank = 0; rank < NUM_RANKS; rank++) {
942 int a = 0;
943 int b = 0;
944
945 if (!info->
946 populated_ranks[channel][slot]
947 [rank])
948 continue;
949 if (extended_silicon_revision == 4
950 && (info->
951 populated_ranks_mask[channel] &
952 5) != 5) {
953 if ((info->
954 spd[channel][slot]
955 [REFERENCE_RAW_CARD_USED] &
956 0x1F) == 3) {
957 a = u16_ffd1178[0]
958 [info->
959 clock_speed_index];
960 b = u16_fe0eb8[0][info->
961 clock_speed_index];
962 } else
963 if ((info->
964 spd[channel][slot]
965 [REFERENCE_RAW_CARD_USED]
966 & 0x1F) == 5) {
967 a = u16_ffd1178[1]
968 [info->
969 clock_speed_index];
970 b = u16_fe0eb8[1][info->
971 clock_speed_index];
972 }
973 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100974 min_of_unk_2 = MIN(min_of_unk_2, a);
975 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100976 if (rank == 0) {
977 sum += a;
978 count++;
979 }
980 {
981 int t;
982 t = b +
983 u8_FFFD0EF8[channel]
984 [extended_silicon_revision]
985 [info->
986 mode4030[channel]][info->
987 clock_speed_index];
988 if (unk1 >= t)
989 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100990 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100991 unk1 - t);
992 }
993 }
994 {
995 int t =
996 u8_FFFD17E0[channel]
997 [extended_silicon_revision][info->
998 mode4030
999 [channel]]
1000 [info->clock_speed_index] + min_of_unk_2;
1001 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001002 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001003 }
1004 }
1005
Jacob Garber64fb4a32019-06-10 17:29:18 -06001006 if (count == 0)
1007 die("No memory ranks found for channel %u\n", channel);
1008
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001009 info->avg4044[channel] = sum / count;
1010 info->max4048[channel] = max_of_unk;
1011 }
1012}
1013
1014static void jedec_read(struct raminfo *info,
1015 int channel, int slot, int rank,
1016 int total_rank, u8 addr3, unsigned int value)
1017{
1018 /* Handle mirrored mapping. */
1019 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001020 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1021 ((addr3 >> 1) & 0x10);
1022 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1023 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001024
1025 /* Handle mirrored mapping. */
1026 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1027 value =
1028 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1029 << 1);
1030
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001031 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001032
Felix Held04be2dd2018-07-29 04:53:22 +02001033 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1034 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001035
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001036 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001037}
1038
1039enum {
1040 MR1_RZQ12 = 512,
1041 MR1_RZQ2 = 64,
1042 MR1_RZQ4 = 4,
1043 MR1_ODS34OHM = 2
1044};
1045
1046enum {
1047 MR0_BT_INTERLEAVED = 8,
1048 MR0_DLL_RESET_ON = 256
1049};
1050
1051enum {
1052 MR2_RTT_WR_DISABLED = 0,
1053 MR2_RZQ2 = 1 << 10
1054};
1055
1056static void jedec_init(struct raminfo *info)
1057{
1058 int write_recovery;
1059 int channel, slot, rank;
1060 int total_rank;
1061 int dll_on;
1062 int self_refresh_temperature;
1063 int auto_self_refresh;
1064
1065 auto_self_refresh = 1;
1066 self_refresh_temperature = 1;
1067 if (info->board_lane_delay[3] <= 10) {
1068 if (info->board_lane_delay[3] <= 8)
1069 write_recovery = info->board_lane_delay[3] - 4;
1070 else
1071 write_recovery = 5;
1072 } else {
1073 write_recovery = 6;
1074 }
1075 FOR_POPULATED_RANKS {
1076 auto_self_refresh &=
1077 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1078 self_refresh_temperature &=
1079 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1080 }
1081 if (auto_self_refresh == 1)
1082 self_refresh_temperature = 0;
1083
1084 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1085 || (info->populated_ranks[0][0][0]
1086 && info->populated_ranks[0][1][0])
1087 || (info->populated_ranks[1][0][0]
1088 && info->populated_ranks[1][1][0]));
1089
1090 total_rank = 0;
1091
1092 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1093 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1094 int rzq_reg58e;
1095
1096 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1097 rzq_reg58e = 64;
1098 rtt = MR1_RZQ2;
1099 if (info->clock_speed_index != 0) {
1100 rzq_reg58e = 4;
1101 if (info->populated_ranks_mask[channel] == 3)
1102 rtt = MR1_RZQ4;
1103 }
1104 } else {
1105 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1106 rtt = MR1_RZQ12;
1107 rzq_reg58e = 64;
1108 rtt_wr = MR2_RZQ2;
1109 } else {
1110 rzq_reg58e = 4;
1111 rtt = MR1_RZQ4;
1112 }
1113 }
1114
Felix Held04be2dd2018-07-29 04:53:22 +02001115 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1116 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1117 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1118 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1119 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001120
1121 for (slot = 0; slot < NUM_SLOTS; slot++)
1122 for (rank = 0; rank < NUM_RANKS; rank++)
1123 if (info->populated_ranks[channel][slot][rank]) {
1124 jedec_read(info, channel, slot, rank,
1125 total_rank, 0x28,
1126 rtt_wr | (info->
1127 clock_speed_index
1128 << 3)
1129 | (auto_self_refresh << 6) |
1130 (self_refresh_temperature <<
1131 7));
1132 jedec_read(info, channel, slot, rank,
1133 total_rank, 0x38, 0);
1134 jedec_read(info, channel, slot, rank,
1135 total_rank, 0x18,
1136 rtt | MR1_ODS34OHM);
1137 jedec_read(info, channel, slot, rank,
1138 total_rank, 6,
1139 (dll_on << 12) |
1140 (write_recovery << 9)
1141 | ((info->cas_latency - 4) <<
1142 4) | MR0_BT_INTERLEAVED |
1143 MR0_DLL_RESET_ON);
1144 total_rank++;
1145 }
1146 }
1147}
1148
1149static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1150{
Martin Roth468d02c2019-10-23 21:44:42 -06001151 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001152 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1153 unsigned int channel_0_non_interleaved;
1154
1155 FOR_ALL_RANKS {
1156 if (info->populated_ranks[channel][slot][rank]) {
1157 total_mb[channel] +=
1158 pre_jedec ? 256 : (256 << info->
1159 density[channel][slot] >> info->
1160 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001161 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1162 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1163 (info->is_x16_module[channel][slot] |
1164 ((info->density[channel][slot] + 1) << 1))) |
1165 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001166 }
Felix Held04be2dd2018-07-29 04:53:22 +02001167 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1168 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001169 }
1170
1171 info->total_memory_mb = total_mb[0] + total_mb[1];
1172
1173 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001174 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001175 info->non_interleaved_part_mb =
1176 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1177 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001178 MCHBAR32(0x100) = channel_0_non_interleaved |
1179 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001180 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001181 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001182}
1183
1184static void program_board_delay(struct raminfo *info)
1185{
1186 int cas_latency_shift;
1187 int some_delay_ns;
1188 int some_delay_3_half_cycles;
1189
Martin Roth468d02c2019-10-23 21:44:42 -06001190 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001191 int high_multiplier;
1192 int lane_3_delay;
1193 int cas_latency_derived;
1194
1195 high_multiplier = 0;
1196 some_delay_ns = 200;
1197 some_delay_3_half_cycles = 4;
1198 cas_latency_shift = info->silicon_revision == 0
1199 || info->silicon_revision == 1 ? 1 : 0;
1200 if (info->revision < 8) {
1201 some_delay_ns = 600;
1202 cas_latency_shift = 0;
1203 }
1204 {
1205 int speed_bit;
1206 speed_bit =
1207 ((info->clock_speed_index > 1
1208 || (info->silicon_revision != 2
1209 && info->silicon_revision != 3))) ^ (info->revision >=
1210 0x10);
1211 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1212 3, 1);
1213 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1214 3, 1);
1215 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1216 && (info->silicon_revision == 2
1217 || info->silicon_revision == 3))
1218 rmw_1d0(0x116, 5, 2, 4, 1);
1219 }
Felix Held04be2dd2018-07-29 04:53:22 +02001220 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1221 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001222
Felix Held04be2dd2018-07-29 04:53:22 +02001223 MCHBAR8(0x124) = info->board_lane_delay[4] +
1224 ((frequency_01(info) + 999) / 1000);
1225 MCHBAR16(0x125) = 0x1360;
1226 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001227 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001228 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001229 high_multiplier = 1;
1230 some_delay_2_half_cycles = ps_to_halfcycles(info,
1231 ((3 *
1232 fsbcycle_ps(info))
1233 >> 1) +
1234 (halfcycle_ps(info)
1235 *
1236 reg178_min[info->
1237 clock_speed_index]
1238 >> 6)
1239 +
1240 4 *
1241 halfcycle_ps(info)
1242 + 2230);
1243 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001244 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001245 (frequency_11(info) * 2) * (28 -
1246 some_delay_2_half_cycles) /
1247 (frequency_11(info) * 2 -
1248 4 * (info->fsb_frequency))) >> 3, 7);
1249 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001250 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001251 some_delay_3_half_cycles = 3;
1252 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001253 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1254 MCHBAR32(0x224 + (channel << 10)) =
1255 (info->max_slots_used_in_channel - 1) |
1256 ((info->cas_latency - 5 - info->clock_speed_index)
1257 << 21) | ((info->max_slots_used_in_channel +
1258 info->cas_latency - cas_latency_shift - 4) << 16) |
1259 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1260 ((info->cas_latency - info->clock_speed_index +
1261 info->max_slots_used_in_channel - 6) << 8);
1262 MCHBAR32(0x228 + (channel << 10)) =
1263 info->max_slots_used_in_channel;
1264 MCHBAR8(0x239 + (channel << 10)) = 32;
1265 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1266 (some_delay_3_half_cycles << 25) | 0x840000;
1267 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1268 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1269 MCHBAR32(0x24c + (channel << 10)) =
1270 ((!!info->clock_speed_index) << 17) |
1271 (((2 + info->clock_speed_index -
1272 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001273
Felix Held04be2dd2018-07-29 04:53:22 +02001274 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1275 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1276 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001277
1278 write_500(info, channel,
1279 ((!info->populated_ranks[channel][1][1])
1280 | (!info->populated_ranks[channel][1][0] << 1)
1281 | (!info->populated_ranks[channel][0][1] << 2)
1282 | (!info->populated_ranks[channel][0][0] << 3)),
1283 0x4c9, 4, 1);
1284 }
1285
Felix Held22ca8cb2018-07-29 05:09:44 +02001286 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001287 {
1288 u8 freq_divisor = 2;
1289 if (info->fsb_frequency == frequency_11(info))
1290 freq_divisor = 3;
1291 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1292 freq_divisor = 1;
1293 else
1294 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001295 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001296 }
1297
1298 if (info->board_lane_delay[3] <= 10) {
1299 if (info->board_lane_delay[3] <= 8)
1300 lane_3_delay = info->board_lane_delay[3];
1301 else
1302 lane_3_delay = 10;
1303 } else {
1304 lane_3_delay = 12;
1305 }
1306 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1307 if (info->clock_speed_index > 1)
1308 cas_latency_derived++;
1309 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001310 MCHBAR32(0x240 + (channel << 10)) =
1311 ((info->clock_speed_index == 0) * 0x11000) |
1312 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1313 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001314 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1315 0x609, 6, 1);
1316 write_500(info, channel,
1317 info->clock_speed_index + 2 * info->cas_latency - 7,
1318 0x601, 6, 1);
1319
Felix Held04be2dd2018-07-29 04:53:22 +02001320 MCHBAR32(0x250 + (channel << 10)) =
1321 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1322 (info->board_lane_delay[7] << 2) |
1323 (info->board_lane_delay[4] << 16) |
1324 (info->board_lane_delay[1] << 25) |
1325 (info->board_lane_delay[1] << 29) | 1;
1326 MCHBAR32(0x254 + (channel << 10)) =
1327 (info->board_lane_delay[1] >> 3) |
1328 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1329 0x80 | (info->board_lane_delay[6] << 1) |
1330 (info->board_lane_delay[2] << 28) |
1331 (cas_latency_derived << 16) | 0x4700000;
1332 MCHBAR32(0x258 + (channel << 10)) =
1333 ((info->board_lane_delay[5] + info->clock_speed_index +
1334 9) << 12) | ((info->clock_speed_index -
1335 info->cas_latency + 12) << 8) |
1336 (info->board_lane_delay[2] << 17) |
1337 (info->board_lane_delay[4] << 24) | 0x47;
1338 MCHBAR32(0x25c + (channel << 10)) =
1339 (info->board_lane_delay[1] << 1) |
1340 (info->board_lane_delay[0] << 8) | 0x1da50000;
1341 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1342 MCHBAR8(0x5f8 + (channel << 10)) =
1343 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001344 }
1345
1346 program_modules_memory_map(info, 1);
1347
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001348 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001349 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1350 MCHBAR16_OR(0x612, 0x100);
1351 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001352 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001353 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001354 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001355 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001356 }
1357}
1358
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001359#define DEFAULT_PCI_MMIO_SIZE 2048
1360#define HOST_BRIDGE PCI_DEVFN(0, 0)
1361
1362static unsigned int get_mmio_size(void)
1363{
1364 const struct device *dev;
1365 const struct northbridge_intel_nehalem_config *cfg = NULL;
1366
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001367 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001368 if (dev)
1369 cfg = dev->chip_info;
1370
1371 /* If this is zero, it just means devicetree.cb didn't set it */
1372 if (!cfg || cfg->pci_mmio_size == 0)
1373 return DEFAULT_PCI_MMIO_SIZE;
1374 else
1375 return cfg->pci_mmio_size;
1376}
1377
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378#define BETTER_MEMORY_MAP 0
1379
1380static void program_total_memory_map(struct raminfo *info)
1381{
1382 unsigned int TOM, TOLUD, TOUUD;
1383 unsigned int quickpath_reserved;
1384 unsigned int REMAPbase;
1385 unsigned int uma_base_igd;
1386 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001387 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001388 int memory_remap;
1389 unsigned int memory_map[8];
1390 int i;
1391 unsigned int current_limit;
1392 unsigned int tseg_base;
1393 int uma_size_igd = 0, uma_size_gtt = 0;
1394
1395 memset(memory_map, 0, sizeof(memory_map));
1396
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001397 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001398 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001399 gav(t);
1400 const int uma_sizes_gtt[16] =
1401 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1402 /* Igd memory */
1403 const int uma_sizes_igd[16] = {
1404 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1405 256, 512
1406 };
1407
1408 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1409 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1410 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001411
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001412 mmio_size = get_mmio_size();
1413
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001414 TOM = info->total_memory_mb;
1415 if (TOM == 4096)
1416 TOM = 4032;
1417 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001418 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001419 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001420 memory_remap = 0;
1421 if (TOUUD - TOLUD > 64) {
1422 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001423 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 TOUUD = TOUUD - TOLUD + 4096;
1425 }
1426 if (TOUUD > 4096)
1427 memory_map[2] = TOUUD | 1;
1428 quickpath_reserved = 0;
1429
Jacob Garber975a7e32019-06-10 16:32:47 -06001430 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001431
Jacob Garber975a7e32019-06-10 16:32:47 -06001432 gav(t);
1433
1434 if (t & 0x800) {
1435 u32 shift = t >> 20;
1436 if (shift == 0)
1437 die("Quickpath value is 0\n");
1438 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001440
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001441 if (memory_remap)
1442 TOUUD -= quickpath_reserved;
1443
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001444 uma_base_igd = TOLUD - uma_size_igd;
1445 uma_base_gtt = uma_base_igd - uma_size_gtt;
1446 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1447 if (!memory_remap)
1448 tseg_base -= quickpath_reserved;
1449 tseg_base = ALIGN_DOWN(tseg_base, 8);
1450
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001451 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1452 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001453 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001454 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1455 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001457 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458
1459 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001460 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1461 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001463 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464
1465 current_limit = 0;
1466 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1467 memory_map[1] = 4096;
1468 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001469 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001470 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1472 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001473 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001474 }
1475}
1476
1477static void collect_system_info(struct raminfo *info)
1478{
1479 u32 capid0[3];
1480 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001481 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001482
1483 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001484 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1485 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001486
1487 if (!info->heci_bar)
1488 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001489 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001490 if (!info->memory_reserved_for_heci_mb) {
1491 /* Wait for ME to be ready */
1492 intel_early_me_init();
1493 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1494 }
1495
1496 for (i = 0; i < 3; i++)
1497 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001498 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1499 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001500 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1501
1502 if ((capid0[1] >> 11) & 1)
1503 info->uma_enabled = 0;
1504 else
1505 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001506 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1508 info->silicon_revision = 0;
1509
1510 if (capid0[2] & 2) {
1511 info->silicon_revision = 0;
1512 info->max_supported_clock_speed_index = 2;
1513 for (channel = 0; channel < NUM_CHANNELS; channel++)
1514 if (info->populated_ranks[channel][0][0]
1515 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1516 3) {
1517 info->silicon_revision = 2;
1518 info->max_supported_clock_speed_index = 1;
1519 }
1520 } else {
1521 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1522 case 1:
1523 case 2:
1524 info->silicon_revision = 3;
1525 break;
1526 case 3:
1527 info->silicon_revision = 0;
1528 break;
1529 case 0:
1530 info->silicon_revision = 2;
1531 break;
1532 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001533 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001534 case 0x40:
1535 info->silicon_revision = 0;
1536 break;
1537 case 0x48:
1538 info->silicon_revision = 1;
1539 break;
1540 }
1541 }
1542}
1543
1544static void write_training_data(struct raminfo *info)
1545{
1546 int tm, channel, slot, rank, lane;
1547 if (info->revision < 8)
1548 return;
1549
1550 for (tm = 0; tm < 4; tm++)
1551 for (channel = 0; channel < NUM_CHANNELS; channel++)
1552 for (slot = 0; slot < NUM_SLOTS; slot++)
1553 for (rank = 0; rank < NUM_RANKS; rank++)
1554 for (lane = 0; lane < 9; lane++)
1555 write_500(info, channel,
1556 info->
1557 cached_training->
1558 lane_timings[tm]
1559 [channel][slot][rank]
1560 [lane],
1561 get_timing_register_addr
1562 (lane, tm, slot,
1563 rank), 9, 0);
1564 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1565 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1566}
1567
1568static void dump_timings(struct raminfo *info)
1569{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 slot, rank);
1575 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001576 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001578 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 read_500(info, channel,
1580 get_timing_register_addr
1581 (lane, i, slot, rank),
1582 9),
1583 info->training.
1584 lane_timings[i][channel][slot][rank]
1585 [lane]);
1586 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001587 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 }
1589 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001590 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001591 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001592 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001593 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594}
1595
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001596/* Read timings and other registers that need to be restored verbatim and
1597 put them to CBMEM.
1598 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599static void save_timings(struct raminfo *info)
1600{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602 int channel, slot, rank, lane, i;
1603
1604 train = info->training;
1605 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1606 for (i = 0; i < 4; i++)
1607 train.lane_timings[i][channel][slot][rank][lane] =
1608 read_500(info, channel,
1609 get_timing_register_addr(lane, i, slot,
1610 rank), 9);
1611 train.reg_178 = read_1d0(0x178, 7);
1612 train.reg_10b = read_1d0(0x10b, 6);
1613
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001614 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1615 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001616 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001617 train.reg274265[channel][0] = reg32 >> 16;
1618 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001619 train.reg274265[channel][2] =
1620 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001621 }
Felix Held04be2dd2018-07-29 04:53:22 +02001622 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1623 train.reg_6dc = MCHBAR32(0x6dc);
1624 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001625
Arthur Heymansb3282092019-04-14 17:53:28 +02001626 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1627 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001628
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001630 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1631 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001632}
1633
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634static const struct ram_training *get_cached_training(void)
1635{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001636 struct region_device rdev;
1637 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1638 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001640 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001642
1643/* FIXME: add timeout. */
1644static void wait_heci_ready(void)
1645{
Felix Held04be2dd2018-07-29 04:53:22 +02001646 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1647 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001648 write32((DEFAULT_HECIBAR + 0x4),
1649 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650}
1651
1652/* FIXME: add timeout. */
1653static void wait_heci_cb_avail(int len)
1654{
1655 union {
1656 struct mei_csr csr;
1657 u32 raw;
1658 } csr;
1659
Felix Held22ca8cb2018-07-29 05:09:44 +02001660 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1661 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001662
1663 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001664 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665 while (len >
1666 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001667 csr.csr.buffer_read_ptr))
1668 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669}
1670
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001671static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672{
1673 int len = (head->length + 3) / 4;
1674 int i;
1675
1676 wait_heci_cb_avail(len + 1);
1677
1678 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001681 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001682
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001683 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1684 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001685}
1686
1687static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001688send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689{
1690 struct mei_header head;
1691 int maxlen;
1692
1693 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001694 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695
1696 while (len) {
1697 int cur = len;
1698 if (cur > maxlen) {
1699 cur = maxlen;
1700 head.is_complete = 0;
1701 } else
1702 head.is_complete = 1;
1703 head.length = cur;
1704 head.reserved = 0;
1705 head.client_address = clientaddress;
1706 head.host_address = hostaddress;
1707 send_heci_packet(&head, (u32 *) msg);
1708 len -= cur;
1709 msg += cur;
1710 }
1711}
1712
1713/* FIXME: Add timeout. */
1714static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001715recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1716 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717{
1718 union {
1719 struct mei_csr csr;
1720 u32 raw;
1721 } csr;
1722 int i = 0;
1723
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001724 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001726 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727 }
Felix Held04be2dd2018-07-29 04:53:22 +02001728 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1729 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001732 write32(DEFAULT_HECIBAR + 0x4,
1733 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 *packet_size = 0;
1735 return 0;
1736 }
1737 if (head->length + 4 > 4 * csr.csr.buffer_depth
1738 || head->length > *packet_size) {
1739 *packet_size = 0;
1740 return -1;
1741 }
1742
1743 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001744 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001745 while (((head->length + 3) >> 2) >
1746 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1747 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001748
1749 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001750 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001751 *packet_size = head->length;
1752 if (!csr.csr.ready)
1753 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001754 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755 return 0;
1756}
1757
1758/* FIXME: Add timeout. */
1759static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001760recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001761{
1762 struct mei_header head;
1763 int current_position;
1764
1765 current_position = 0;
1766 while (1) {
1767 u32 current_size;
1768 current_size = *message_size - current_position;
1769 if (recv_heci_packet
1770 (info, &head, message + (current_position >> 2),
1771 &current_size) == -1)
1772 break;
1773 if (!current_size)
1774 break;
1775 current_position += current_size;
1776 if (head.is_complete) {
1777 *message_size = current_position;
1778 return 0;
1779 }
1780
1781 if (current_position >= *message_size)
1782 break;
1783 }
1784 *message_size = 0;
1785 return -1;
1786}
1787
1788static void send_heci_uma_message(struct raminfo *info)
1789{
1790 struct uma_reply {
1791 u8 group_id;
1792 u8 command;
1793 u8 reserved;
1794 u8 result;
1795 u8 field2;
1796 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001797 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001798 struct uma_message {
1799 u8 group_id;
1800 u8 cmd;
1801 u8 reserved;
1802 u8 result;
1803 u32 c2;
1804 u64 heci_uma_addr;
1805 u32 memory_reserved_for_heci_mb;
1806 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001807 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001808 0, MKHI_SET_UMA, 0, 0,
1809 0x82,
1810 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1811 u32 reply_size;
1812
1813 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1814
1815 reply_size = sizeof(reply);
1816 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1817 return;
1818
1819 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1820 die("HECI init failed\n");
1821}
1822
1823static void setup_heci_uma(struct raminfo *info)
1824{
1825 u32 reg44;
1826
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001827 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828 info->memory_reserved_for_heci_mb = 0;
1829 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001830 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831 return;
1832
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001833 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001834 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1835 info->heci_uma_addr =
1836 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001837 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838 info->memory_reserved_for_heci_mb)) << 20;
1839
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001840 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001842 write32(DEFAULT_DMIBAR + 0x14,
1843 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1844 write32(DEFAULT_RCBA + 0x14,
1845 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1846 write32(DEFAULT_DMIBAR + 0x20,
1847 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1848 write32(DEFAULT_RCBA + 0x20,
1849 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1850 write32(DEFAULT_DMIBAR + 0x2c,
1851 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1852 write32(DEFAULT_RCBA + 0x30,
1853 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1854 write32(DEFAULT_DMIBAR + 0x38,
1855 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1856 write32(DEFAULT_RCBA + 0x40,
1857 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001858
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001859 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1860 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001861 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1862 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1863 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001864 }
1865
Felix Held04be2dd2018-07-29 04:53:22 +02001866 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001867
1868 send_heci_uma_message(info);
1869
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001870 pci_write_config32(HECIDEV, 0x10, 0x0);
1871 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001872
1873}
1874
1875static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1876{
1877 int ranks_in_channel;
1878 ranks_in_channel = info->populated_ranks[channel][0][0]
1879 + info->populated_ranks[channel][0][1]
1880 + info->populated_ranks[channel][1][0]
1881 + info->populated_ranks[channel][1][1];
1882
1883 /* empty channel */
1884 if (ranks_in_channel == 0)
1885 return 1;
1886
1887 if (ranks_in_channel != ranks)
1888 return 0;
1889 /* single slot */
1890 if (info->populated_ranks[channel][0][0] !=
1891 info->populated_ranks[channel][1][0])
1892 return 1;
1893 if (info->populated_ranks[channel][0][1] !=
1894 info->populated_ranks[channel][1][1])
1895 return 1;
1896 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1897 return 0;
1898 if (info->density[channel][0] != info->density[channel][1])
1899 return 0;
1900 return 1;
1901}
1902
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001903static void read_4090(struct raminfo *info)
1904{
1905 int i, channel, slot, rank, lane;
1906 for (i = 0; i < 2; i++)
1907 for (slot = 0; slot < NUM_SLOTS; slot++)
1908 for (rank = 0; rank < NUM_RANKS; rank++)
1909 for (lane = 0; lane < 9; lane++)
1910 info->training.
1911 lane_timings[0][i][slot][rank][lane]
1912 = 32;
1913
1914 for (i = 1; i < 4; i++)
1915 for (channel = 0; channel < NUM_CHANNELS; channel++)
1916 for (slot = 0; slot < NUM_SLOTS; slot++)
1917 for (rank = 0; rank < NUM_RANKS; rank++)
1918 for (lane = 0; lane < 9; lane++) {
1919 info->training.
1920 lane_timings[i][channel]
1921 [slot][rank][lane] =
1922 read_500(info, channel,
1923 get_timing_register_addr
1924 (lane, i, slot,
1925 rank), 9)
1926 + (i == 1) * 11; // !!!!
1927 }
1928
1929}
1930
1931static u32 get_etalon2(int flip, u32 addr)
1932{
1933 const u16 invmask[] = {
1934 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1935 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1936 };
1937 u32 ret;
1938 u32 comp4 = addr / 480;
1939 addr %= 480;
1940 u32 comp1 = addr & 0xf;
1941 u32 comp2 = (addr >> 4) & 1;
1942 u32 comp3 = addr >> 5;
1943
1944 if (comp4)
1945 ret = 0x1010101 << (comp4 - 1);
1946 else
1947 ret = 0;
1948 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1949 ret = ~ret;
1950
1951 return ret;
1952}
1953
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001954static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001955{
1956 msr_t msr = {.lo = 0, .hi = 0 };
1957
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001958 wrmsr(MTRR_PHYS_BASE(3), msr);
1959 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001960}
1961
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001962static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001963{
1964 msr_t msr;
1965 msr.lo = base | MTRR_TYPE_WRPROT;
1966 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001967 wrmsr(MTRR_PHYS_BASE(3), msr);
1968 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969 & 0xffffffff);
1970 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001971 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972}
1973
1974static void flush_cache(u32 start, u32 size)
1975{
1976 u32 end;
1977 u32 addr;
1978
1979 end = start + (ALIGN_DOWN(size + 4096, 4096));
1980 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001981 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001982}
1983
1984static void clear_errors(void)
1985{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001986 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001987}
1988
1989static void write_testing(struct raminfo *info, int totalrank, int flip)
1990{
1991 int nwrites = 0;
1992 /* in 8-byte units. */
1993 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001994 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001996 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001997 for (offset = 0; offset < 9 * 480; offset += 2) {
1998 write32(base + offset * 8, get_etalon2(flip, offset));
1999 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2000 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2001 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2002 nwrites += 4;
2003 if (nwrites >= 320) {
2004 clear_errors();
2005 nwrites = 0;
2006 }
2007 }
2008}
2009
2010static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2011{
2012 u8 failmask = 0;
2013 int i;
2014 int comp1, comp2, comp3;
2015 u32 failxor[2] = { 0, 0 };
2016
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002017 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002018
2019 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2020 for (comp1 = 0; comp1 < 4; comp1++)
2021 for (comp2 = 0; comp2 < 60; comp2++) {
2022 u32 re[4];
2023 u32 curroffset =
2024 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2025 read128((total_rank << 28) | (curroffset << 3),
2026 (u64 *) re);
2027 failxor[0] |=
2028 get_etalon2(flip, curroffset) ^ re[0];
2029 failxor[1] |=
2030 get_etalon2(flip, curroffset) ^ re[1];
2031 failxor[0] |=
2032 get_etalon2(flip, curroffset | 1) ^ re[2];
2033 failxor[1] |=
2034 get_etalon2(flip, curroffset | 1) ^ re[3];
2035 }
2036 for (i = 0; i < 8; i++)
2037 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2038 failmask |= 1 << i;
2039 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002040 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002041 flush_cache((total_rank << 28), 1728 * 5 * 4);
2042 return failmask;
2043}
2044
2045const u32 seed1[0x18] = {
2046 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2047 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2048 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2049 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2050 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2051 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2052};
2053
2054static u32 get_seed2(int a, int b)
2055{
2056 const u32 seed2[5] = {
2057 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2058 0x5b6db6db,
2059 };
2060 u32 r;
2061 r = seed2[(a + (a >= 10)) / 5];
2062 return b ? ~r : r;
2063}
2064
2065static int make_shift(int comp2, int comp5, int x)
2066{
2067 const u8 seed3[32] = {
2068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2069 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2070 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2071 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2072 };
2073
2074 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2075}
2076
2077static u32 get_etalon(int flip, u32 addr)
2078{
2079 u32 mask_byte = 0;
2080 int comp1 = (addr >> 1) & 1;
2081 int comp2 = (addr >> 3) & 0x1f;
2082 int comp3 = (addr >> 8) & 0xf;
2083 int comp4 = (addr >> 12) & 0xf;
2084 int comp5 = (addr >> 16) & 0x1f;
2085 u32 mask_bit = ~(0x10001 << comp3);
2086 u32 part1;
2087 u32 part2;
2088 int byte;
2089
2090 part2 =
2091 ((seed1[comp5] >>
2092 make_shift(comp2, comp5,
2093 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2094 part1 =
2095 ((seed1[comp5] >>
2096 make_shift(comp2, comp5,
2097 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2098
2099 for (byte = 0; byte < 4; byte++)
2100 if ((get_seed2(comp5, comp4) >>
2101 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2102 mask_byte |= 0xff << (8 * byte);
2103
2104 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2105 (comp3 + 16));
2106}
2107
2108static void
2109write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2110 char flip)
2111{
2112 int i;
2113 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002114 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2115 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002116}
2117
2118static u8
2119check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2120 char flip)
2121{
2122 u8 failmask = 0;
2123 u32 failxor[2];
2124 int i;
2125 int comp1, comp2, comp3;
2126
2127 failxor[0] = 0;
2128 failxor[1] = 0;
2129
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002130 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002131 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2132 for (comp1 = 0; comp1 < 16; comp1++)
2133 for (comp2 = 0; comp2 < 64; comp2++) {
2134 u32 addr =
2135 (totalrank << 28) | (region << 25) | (block
2136 << 16)
2137 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2138 2);
2139 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002140 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002141 }
2142 for (i = 0; i < 8; i++)
2143 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2144 failmask |= 1 << i;
2145 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002146 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002147 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2148 return failmask;
2149}
2150
2151static int check_bounded(unsigned short *vals, u16 bound)
2152{
2153 int i;
2154
2155 for (i = 0; i < 8; i++)
2156 if (vals[i] < bound)
2157 return 0;
2158 return 1;
2159}
2160
2161enum state {
2162 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2163};
2164
2165static int validate_state(enum state *in)
2166{
2167 int i;
2168 for (i = 0; i < 8; i++)
2169 if (in[i] != COMPLETE)
2170 return 0;
2171 return 1;
2172}
2173
2174static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002175do_fsm(enum state *state, u16 *counter,
2176 u8 fail_mask, int margin, int uplimit,
2177 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002178{
2179 int lane;
2180
2181 for (lane = 0; lane < 8; lane++) {
2182 int is_fail = (fail_mask >> lane) & 1;
2183 switch (state[lane]) {
2184 case BEFORE_USABLE:
2185 if (!is_fail) {
2186 counter[lane] = 1;
2187 state[lane] = AT_USABLE;
2188 break;
2189 }
2190 counter[lane] = 0;
2191 state[lane] = BEFORE_USABLE;
2192 break;
2193 case AT_USABLE:
2194 if (!is_fail) {
2195 ++counter[lane];
2196 if (counter[lane] >= margin) {
2197 state[lane] = AT_MARGIN;
2198 res_low[lane] = val - margin + 1;
2199 break;
2200 }
2201 state[lane] = 1;
2202 break;
2203 }
2204 counter[lane] = 0;
2205 state[lane] = BEFORE_USABLE;
2206 break;
2207 case AT_MARGIN:
2208 if (is_fail) {
2209 state[lane] = COMPLETE;
2210 res_high[lane] = val - 1;
2211 } else {
2212 counter[lane]++;
2213 state[lane] = AT_MARGIN;
2214 if (val == uplimit) {
2215 state[lane] = COMPLETE;
2216 res_high[lane] = uplimit;
2217 }
2218 }
2219 break;
2220 case COMPLETE:
2221 break;
2222 }
2223 }
2224}
2225
2226static void
2227train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2228 u8 total_rank, u8 reg_178, int first_run, int niter,
2229 timing_bounds_t * timings)
2230{
2231 int lane;
2232 enum state state[8];
2233 u16 count[8];
2234 u8 lower_usable[8];
2235 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002236 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002237 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002238 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002239
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002240 for (i = 0; i < 8; i++)
2241 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002242
2243 if (!first_run) {
2244 int is_all_ok = 1;
2245 for (lane = 0; lane < 8; lane++)
2246 if (timings[reg_178][channel][slot][rank][lane].
2247 smallest ==
2248 timings[reg_178][channel][slot][rank][lane].
2249 largest) {
2250 timings[reg_178][channel][slot][rank][lane].
2251 smallest = 0;
2252 timings[reg_178][channel][slot][rank][lane].
2253 largest = 0;
2254 is_all_ok = 0;
2255 }
2256 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002257 for (i = 0; i < 8; i++)
2258 state[i] = COMPLETE;
2259 }
2260 }
2261
2262 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2263 u8 failmask = 0;
2264 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2265 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2266 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002267 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002268 do_fsm(state, count, failmask, 5, 47, lower_usable,
2269 upper_usable, reg1b3);
2270 }
2271
2272 if (reg1b3) {
2273 write_1d0(0, 0x1b3, 6, 1);
2274 write_1d0(0, 0x1a3, 6, 1);
2275 for (lane = 0; lane < 8; lane++) {
2276 if (state[lane] == COMPLETE) {
2277 timings[reg_178][channel][slot][rank][lane].
2278 smallest =
2279 lower_usable[lane] +
2280 (info->training.
2281 lane_timings[0][channel][slot][rank][lane]
2282 & 0x3F) - 32;
2283 timings[reg_178][channel][slot][rank][lane].
2284 largest =
2285 upper_usable[lane] +
2286 (info->training.
2287 lane_timings[0][channel][slot][rank][lane]
2288 & 0x3F) - 32;
2289 }
2290 }
2291 }
2292
2293 if (!first_run) {
2294 for (lane = 0; lane < 8; lane++)
2295 if (state[lane] == COMPLETE) {
2296 write_500(info, channel,
2297 timings[reg_178][channel][slot][rank]
2298 [lane].smallest,
2299 get_timing_register_addr(lane, 0,
2300 slot, rank),
2301 9, 1);
2302 write_500(info, channel,
2303 timings[reg_178][channel][slot][rank]
2304 [lane].smallest +
2305 info->training.
2306 lane_timings[1][channel][slot][rank]
2307 [lane]
2308 -
2309 info->training.
2310 lane_timings[0][channel][slot][rank]
2311 [lane], get_timing_register_addr(lane,
2312 1,
2313 slot,
2314 rank),
2315 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002316 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002317 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002318 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002319
2320 do {
2321 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 for (i = 0; i < niter; i++) {
2323 if (failmask == 0xFF)
2324 break;
2325 failmask |=
2326 check_testing_type2(info, total_rank, 2, i,
2327 0);
2328 failmask |=
2329 check_testing_type2(info, total_rank, 3, i,
2330 1);
2331 }
Felix Held04be2dd2018-07-29 04:53:22 +02002332 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002333 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002334 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002335 if ((1 << lane) & failmask) {
2336 if (timings[reg_178][channel]
2337 [slot][rank][lane].
2338 largest <=
2339 timings[reg_178][channel]
2340 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002341 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002342 [lane] = -1;
2343 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002344 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002345 [lane] = 0;
2346 timings[reg_178]
2347 [channel][slot]
2348 [rank][lane].
2349 smallest++;
2350 write_500(info, channel,
2351 timings
2352 [reg_178]
2353 [channel]
2354 [slot][rank]
2355 [lane].
2356 smallest,
2357 get_timing_register_addr
2358 (lane, 0,
2359 slot, rank),
2360 9, 1);
2361 write_500(info, channel,
2362 timings
2363 [reg_178]
2364 [channel]
2365 [slot][rank]
2366 [lane].
2367 smallest +
2368 info->
2369 training.
2370 lane_timings
2371 [1][channel]
2372 [slot][rank]
2373 [lane]
2374 -
2375 info->
2376 training.
2377 lane_timings
2378 [0][channel]
2379 [slot][rank]
2380 [lane],
2381 get_timing_register_addr
2382 (lane, 1,
2383 slot, rank),
2384 9, 1);
2385 }
2386 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002387 num_successfully_checked[lane]
2388 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002389 }
2390 }
Felix Held04be2dd2018-07-29 04:53:22 +02002391 while (!check_bounded(num_successfully_checked, 2))
2392 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002393
2394 for (lane = 0; lane < 8; lane++)
2395 if (state[lane] == COMPLETE) {
2396 write_500(info, channel,
2397 timings[reg_178][channel][slot][rank]
2398 [lane].largest,
2399 get_timing_register_addr(lane, 0,
2400 slot, rank),
2401 9, 1);
2402 write_500(info, channel,
2403 timings[reg_178][channel][slot][rank]
2404 [lane].largest +
2405 info->training.
2406 lane_timings[1][channel][slot][rank]
2407 [lane]
2408 -
2409 info->training.
2410 lane_timings[0][channel][slot][rank]
2411 [lane], get_timing_register_addr(lane,
2412 1,
2413 slot,
2414 rank),
2415 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002416 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002417 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002418 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002419
2420 do {
2421 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002422 for (i = 0; i < niter; i++) {
2423 if (failmask == 0xFF)
2424 break;
2425 failmask |=
2426 check_testing_type2(info, total_rank, 2, i,
2427 0);
2428 failmask |=
2429 check_testing_type2(info, total_rank, 3, i,
2430 1);
2431 }
2432
Felix Held04be2dd2018-07-29 04:53:22 +02002433 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002435 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002436 if ((1 << lane) & failmask) {
2437 if (timings[reg_178][channel]
2438 [slot][rank][lane].
2439 largest <=
2440 timings[reg_178][channel]
2441 [slot][rank][lane].
2442 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002443 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002444 [lane] = -1;
2445 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002446 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002447 [lane] = 0;
2448 timings[reg_178]
2449 [channel][slot]
2450 [rank][lane].
2451 largest--;
2452 write_500(info, channel,
2453 timings
2454 [reg_178]
2455 [channel]
2456 [slot][rank]
2457 [lane].
2458 largest,
2459 get_timing_register_addr
2460 (lane, 0,
2461 slot, rank),
2462 9, 1);
2463 write_500(info, channel,
2464 timings
2465 [reg_178]
2466 [channel]
2467 [slot][rank]
2468 [lane].
2469 largest +
2470 info->
2471 training.
2472 lane_timings
2473 [1][channel]
2474 [slot][rank]
2475 [lane]
2476 -
2477 info->
2478 training.
2479 lane_timings
2480 [0][channel]
2481 [slot][rank]
2482 [lane],
2483 get_timing_register_addr
2484 (lane, 1,
2485 slot, rank),
2486 9, 1);
2487 }
2488 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002489 num_successfully_checked[lane]
2490 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002491 }
2492 }
2493 }
Felix Held04be2dd2018-07-29 04:53:22 +02002494 while (!check_bounded(num_successfully_checked, 3))
2495 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002496
2497 for (lane = 0; lane < 8; lane++) {
2498 write_500(info, channel,
2499 info->training.
2500 lane_timings[0][channel][slot][rank][lane],
2501 get_timing_register_addr(lane, 0, slot, rank),
2502 9, 1);
2503 write_500(info, channel,
2504 info->training.
2505 lane_timings[1][channel][slot][rank][lane],
2506 get_timing_register_addr(lane, 1, slot, rank),
2507 9, 1);
2508 if (timings[reg_178][channel][slot][rank][lane].
2509 largest <=
2510 timings[reg_178][channel][slot][rank][lane].
2511 smallest) {
2512 timings[reg_178][channel][slot][rank][lane].
2513 largest = 0;
2514 timings[reg_178][channel][slot][rank][lane].
2515 smallest = 0;
2516 }
2517 }
2518 }
2519}
2520
2521static void set_10b(struct raminfo *info, u8 val)
2522{
2523 int channel;
2524 int slot, rank;
2525 int lane;
2526
2527 if (read_1d0(0x10b, 6) == val)
2528 return;
2529
2530 write_1d0(val, 0x10b, 6, 1);
2531
2532 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2533 u16 reg_500;
2534 reg_500 = read_500(info, channel,
2535 get_timing_register_addr(lane, 0, slot,
2536 rank), 9);
2537 if (val == 1) {
2538 if (lut16[info->clock_speed_index] <= reg_500)
2539 reg_500 -= lut16[info->clock_speed_index];
2540 else
2541 reg_500 = 0;
2542 } else {
2543 reg_500 += lut16[info->clock_speed_index];
2544 }
2545 write_500(info, channel, reg_500,
2546 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2547 }
2548}
2549
2550static void set_ecc(int onoff)
2551{
2552 int channel;
2553 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2554 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002555 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002556 if (onoff)
2557 t |= 1;
2558 else
2559 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002560 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002561 }
2562}
2563
2564static void set_178(u8 val)
2565{
2566 if (val >= 31)
2567 val = val - 31;
2568 else
2569 val = 63 - val;
2570
2571 write_1d0(2 * val, 0x178, 7, 1);
2572}
2573
2574static void
2575write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2576 int type)
2577{
2578 int lane;
2579
2580 for (lane = 0; lane < 8; lane++)
2581 write_500(info, channel,
2582 info->training.
2583 lane_timings[type][channel][slot][rank][lane],
2584 get_timing_register_addr(lane, type, slot, rank), 9,
2585 0);
2586}
2587
2588static void
2589try_timing_offsets(struct raminfo *info, int channel,
2590 int slot, int rank, int totalrank)
2591{
2592 u16 count[8];
2593 enum state state[8];
2594 u8 lower_usable[8], upper_usable[8];
2595 int lane;
2596 int i;
2597 int flip = 1;
2598 int timing_offset;
2599
2600 for (i = 0; i < 8; i++)
2601 state[i] = BEFORE_USABLE;
2602
2603 memset(count, 0, sizeof(count));
2604
2605 for (lane = 0; lane < 8; lane++)
2606 write_500(info, channel,
2607 info->training.
2608 lane_timings[2][channel][slot][rank][lane] + 32,
2609 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2610
2611 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2612 timing_offset++) {
2613 u8 failmask;
2614 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2615 failmask = 0;
2616 for (i = 0; i < 2 && failmask != 0xff; i++) {
2617 flip = !flip;
2618 write_testing(info, totalrank, flip);
2619 failmask |= check_testing(info, totalrank, flip);
2620 }
2621 do_fsm(state, count, failmask, 10, 63, lower_usable,
2622 upper_usable, timing_offset);
2623 }
2624 write_1d0(0, 0x1bb, 6, 1);
2625 dump_timings(info);
2626 if (!validate_state(state))
2627 die("Couldn't discover DRAM timings (1)\n");
2628
2629 for (lane = 0; lane < 8; lane++) {
2630 u8 bias = 0;
2631
2632 if (info->silicon_revision) {
2633 int usable_length;
2634
2635 usable_length = upper_usable[lane] - lower_usable[lane];
2636 if (usable_length >= 20) {
2637 bias = usable_length / 2 - 10;
2638 if (bias >= 2)
2639 bias = 2;
2640 }
2641 }
2642 write_500(info, channel,
2643 info->training.
2644 lane_timings[2][channel][slot][rank][lane] +
2645 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2646 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2647 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2648 info->training.lane_timings[2][channel][slot][rank][lane] +
2649 lower_usable[lane];
2650 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2651 info->training.lane_timings[2][channel][slot][rank][lane] +
2652 upper_usable[lane];
2653 info->training.timing2_offset[channel][slot][rank][lane] =
2654 info->training.lane_timings[2][channel][slot][rank][lane];
2655 }
2656}
2657
2658static u8
2659choose_training(struct raminfo *info, int channel, int slot, int rank,
2660 int lane, timing_bounds_t * timings, u8 center_178)
2661{
2662 u16 central_weight;
2663 u16 side_weight;
2664 unsigned int sum = 0, count = 0;
2665 u8 span;
2666 u8 lower_margin, upper_margin;
2667 u8 reg_178;
2668 u8 result;
2669
2670 span = 12;
2671 central_weight = 20;
2672 side_weight = 20;
2673 if (info->silicon_revision == 1 && channel == 1) {
2674 central_weight = 5;
2675 side_weight = 20;
2676 if ((info->
2677 populated_ranks_mask[1] ^ (info->
2678 populated_ranks_mask[1] >> 2)) &
2679 1)
2680 span = 18;
2681 }
2682 if ((info->populated_ranks_mask[0] & 5) == 5) {
2683 central_weight = 20;
2684 side_weight = 20;
2685 }
2686 if (info->clock_speed_index >= 2
2687 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2688 if (info->silicon_revision == 1) {
2689 switch (channel) {
2690 case 0:
2691 if (lane == 1) {
2692 central_weight = 10;
2693 side_weight = 20;
2694 }
2695 break;
2696 case 1:
2697 if (lane == 6) {
2698 side_weight = 5;
2699 central_weight = 20;
2700 }
2701 break;
2702 }
2703 }
2704 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2705 side_weight = 5;
2706 central_weight = 20;
2707 }
2708 }
2709 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2710 reg_178 += span) {
2711 u8 smallest;
2712 u8 largest;
2713 largest = timings[reg_178][channel][slot][rank][lane].largest;
2714 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2715 if (largest - smallest + 1 >= 5) {
2716 unsigned int weight;
2717 if (reg_178 == center_178)
2718 weight = central_weight;
2719 else
2720 weight = side_weight;
2721 sum += weight * (largest + smallest);
2722 count += weight;
2723 }
2724 }
2725 dump_timings(info);
2726 if (count == 0)
2727 die("Couldn't discover DRAM timings (2)\n");
2728 result = sum / (2 * count);
2729 lower_margin =
2730 result - timings[center_178][channel][slot][rank][lane].smallest;
2731 upper_margin =
2732 timings[center_178][channel][slot][rank][lane].largest - result;
2733 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002734 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002735 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002736 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002737 return result;
2738}
2739
2740#define STANDARD_MIN_MARGIN 5
2741
2742static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2743{
2744 u16 margin[64];
2745 int lane, rank, slot, channel;
2746 u8 reg178;
2747 int count = 0, sum = 0;
2748
2749 for (reg178 = reg178_min[info->clock_speed_index];
2750 reg178 < reg178_max[info->clock_speed_index];
2751 reg178 += reg178_step[info->clock_speed_index]) {
2752 margin[reg178] = -1;
2753 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2754 int curmargin =
2755 timings[reg178][channel][slot][rank][lane].largest -
2756 timings[reg178][channel][slot][rank][lane].
2757 smallest + 1;
2758 if (curmargin < margin[reg178])
2759 margin[reg178] = curmargin;
2760 }
2761 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2762 u16 weight;
2763 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2764 sum += weight * reg178;
2765 count += weight;
2766 }
2767 }
2768 dump_timings(info);
2769 if (count == 0)
2770 die("Couldn't discover DRAM timings (3)\n");
2771
2772 u8 threshold;
2773
2774 for (threshold = 30; threshold >= 5; threshold--) {
2775 int usable_length = 0;
2776 int smallest_fount = 0;
2777 for (reg178 = reg178_min[info->clock_speed_index];
2778 reg178 < reg178_max[info->clock_speed_index];
2779 reg178 += reg178_step[info->clock_speed_index])
2780 if (margin[reg178] >= threshold) {
2781 usable_length +=
2782 reg178_step[info->clock_speed_index];
2783 info->training.reg178_largest =
2784 reg178 -
2785 2 * reg178_step[info->clock_speed_index];
2786
2787 if (!smallest_fount) {
2788 smallest_fount = 1;
2789 info->training.reg178_smallest =
2790 reg178 +
2791 reg178_step[info->
2792 clock_speed_index];
2793 }
2794 }
2795 if (usable_length >= 0x21)
2796 break;
2797 }
2798
2799 return sum / count;
2800}
2801
2802static int check_cached_sanity(struct raminfo *info)
2803{
2804 int lane;
2805 int slot, rank;
2806 int channel;
2807
2808 if (!info->cached_training)
2809 return 0;
2810
2811 for (channel = 0; channel < NUM_CHANNELS; channel++)
2812 for (slot = 0; slot < NUM_SLOTS; slot++)
2813 for (rank = 0; rank < NUM_RANKS; rank++)
2814 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2815 u16 cached_value, estimation_value;
2816 cached_value =
2817 info->cached_training->
2818 lane_timings[1][channel][slot][rank]
2819 [lane];
2820 if (cached_value >= 0x18
2821 && cached_value <= 0x1E7) {
2822 estimation_value =
2823 info->training.
2824 lane_timings[1][channel]
2825 [slot][rank][lane];
2826 if (estimation_value <
2827 cached_value - 24)
2828 return 0;
2829 if (estimation_value >
2830 cached_value + 24)
2831 return 0;
2832 }
2833 }
2834 return 1;
2835}
2836
2837static int try_cached_training(struct raminfo *info)
2838{
2839 u8 saved_243[2];
2840 u8 tm;
2841
2842 int channel, slot, rank, lane;
2843 int flip = 1;
2844 int i, j;
2845
2846 if (!check_cached_sanity(info))
2847 return 0;
2848
2849 info->training.reg178_center = info->cached_training->reg178_center;
2850 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2851 info->training.reg178_largest = info->cached_training->reg178_largest;
2852 memcpy(&info->training.timing_bounds,
2853 &info->cached_training->timing_bounds,
2854 sizeof(info->training.timing_bounds));
2855 memcpy(&info->training.timing_offset,
2856 &info->cached_training->timing_offset,
2857 sizeof(info->training.timing_offset));
2858
2859 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002860 saved_243[0] = MCHBAR8(0x243);
2861 saved_243[1] = MCHBAR8(0x643);
2862 MCHBAR8(0x243) = saved_243[0] | 2;
2863 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002864 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002865 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002866 if (read_1d0(0x10b, 6) & 1)
2867 set_10b(info, 0);
2868 for (tm = 0; tm < 2; tm++) {
2869 int totalrank;
2870
2871 set_178(tm ? info->cached_training->reg178_largest : info->
2872 cached_training->reg178_smallest);
2873
2874 totalrank = 0;
2875 /* Check timing ranges. With i == 0 we check smallest one and with
2876 i == 1 the largest bound. With j == 0 we check that on the bound
2877 it still works whereas with j == 1 we check that just outside of
2878 bound we fail.
2879 */
2880 FOR_POPULATED_RANKS_BACKWARDS {
2881 for (i = 0; i < 2; i++) {
2882 for (lane = 0; lane < 8; lane++) {
2883 write_500(info, channel,
2884 info->cached_training->
2885 timing2_bounds[channel][slot]
2886 [rank][lane][i],
2887 get_timing_register_addr(lane,
2888 3,
2889 slot,
2890 rank),
2891 9, 1);
2892
2893 if (!i)
2894 write_500(info, channel,
2895 info->
2896 cached_training->
2897 timing2_offset
2898 [channel][slot][rank]
2899 [lane],
2900 get_timing_register_addr
2901 (lane, 2, slot, rank),
2902 9, 1);
2903 write_500(info, channel,
2904 i ? info->cached_training->
2905 timing_bounds[tm][channel]
2906 [slot][rank][lane].
2907 largest : info->
2908 cached_training->
2909 timing_bounds[tm][channel]
2910 [slot][rank][lane].smallest,
2911 get_timing_register_addr(lane,
2912 0,
2913 slot,
2914 rank),
2915 9, 1);
2916 write_500(info, channel,
2917 info->cached_training->
2918 timing_offset[channel][slot]
2919 [rank][lane] +
2920 (i ? info->cached_training->
2921 timing_bounds[tm][channel]
2922 [slot][rank][lane].
2923 largest : info->
2924 cached_training->
2925 timing_bounds[tm][channel]
2926 [slot][rank][lane].
2927 smallest) - 64,
2928 get_timing_register_addr(lane,
2929 1,
2930 slot,
2931 rank),
2932 9, 1);
2933 }
2934 for (j = 0; j < 2; j++) {
2935 u8 failmask;
2936 u8 expected_failmask;
2937 char reg1b3;
2938
2939 reg1b3 = (j == 1) + 4;
2940 reg1b3 =
2941 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2942 write_1d0(reg1b3, 0x1bb, 6, 1);
2943 write_1d0(reg1b3, 0x1b3, 6, 1);
2944 write_1d0(reg1b3, 0x1a3, 6, 1);
2945
2946 flip = !flip;
2947 write_testing(info, totalrank, flip);
2948 failmask =
2949 check_testing(info, totalrank,
2950 flip);
2951 expected_failmask =
2952 j == 0 ? 0x00 : 0xff;
2953 if (failmask != expected_failmask)
2954 goto fail;
2955 }
2956 }
2957 totalrank++;
2958 }
2959 }
2960
2961 set_178(info->cached_training->reg178_center);
2962 if (info->use_ecc)
2963 set_ecc(1);
2964 write_training_data(info);
2965 write_1d0(0, 322, 3, 1);
2966 info->training = *info->cached_training;
2967
2968 write_1d0(0, 0x1bb, 6, 1);
2969 write_1d0(0, 0x1b3, 6, 1);
2970 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002971 MCHBAR8(0x243) = saved_243[0];
2972 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002973
2974 return 1;
2975
2976fail:
2977 FOR_POPULATED_RANKS {
2978 write_500_timings_type(info, channel, slot, rank, 1);
2979 write_500_timings_type(info, channel, slot, rank, 2);
2980 write_500_timings_type(info, channel, slot, rank, 3);
2981 }
2982
2983 write_1d0(0, 0x1bb, 6, 1);
2984 write_1d0(0, 0x1b3, 6, 1);
2985 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002986 MCHBAR8(0x243) = saved_243[0];
2987 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002988
2989 return 0;
2990}
2991
2992static void do_ram_training(struct raminfo *info)
2993{
2994 u8 saved_243[2];
2995 int totalrank = 0;
2996 u8 reg_178;
2997 int niter;
2998
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002999 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003000 int lane, rank, slot, channel;
3001 u8 reg178_center;
3002
3003 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003004 saved_243[0] = MCHBAR8(0x243);
3005 saved_243[1] = MCHBAR8(0x643);
3006 MCHBAR8(0x243) = saved_243[0] | 2;
3007 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003008 switch (info->clock_speed_index) {
3009 case 0:
3010 niter = 5;
3011 break;
3012 case 1:
3013 niter = 10;
3014 break;
3015 default:
3016 niter = 19;
3017 break;
3018 }
3019 set_ecc(0);
3020
3021 FOR_POPULATED_RANKS_BACKWARDS {
3022 int i;
3023
3024 write_500_timings_type(info, channel, slot, rank, 0);
3025
3026 write_testing(info, totalrank, 0);
3027 for (i = 0; i < niter; i++) {
3028 write_testing_type2(info, totalrank, 2, i, 0);
3029 write_testing_type2(info, totalrank, 3, i, 1);
3030 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003031 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003032 totalrank++;
3033 }
3034
3035 if (reg178_min[info->clock_speed_index] <
3036 reg178_max[info->clock_speed_index])
3037 memset(timings[reg178_min[info->clock_speed_index]], 0,
3038 sizeof(timings[0]) *
3039 (reg178_max[info->clock_speed_index] -
3040 reg178_min[info->clock_speed_index]));
3041 for (reg_178 = reg178_min[info->clock_speed_index];
3042 reg_178 < reg178_max[info->clock_speed_index];
3043 reg_178 += reg178_step[info->clock_speed_index]) {
3044 totalrank = 0;
3045 set_178(reg_178);
3046 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3047 for (slot = 0; slot < NUM_SLOTS; slot++)
3048 for (rank = 0; rank < NUM_RANKS; rank++) {
3049 memset(&timings[reg_178][channel][slot]
3050 [rank][0].smallest, 0, 16);
3051 if (info->
3052 populated_ranks[channel][slot]
3053 [rank]) {
3054 train_ram_at_178(info, channel,
3055 slot, rank,
3056 totalrank,
3057 reg_178, 1,
3058 niter,
3059 timings);
3060 totalrank++;
3061 }
3062 }
3063 }
3064
3065 reg178_center = choose_reg178(info, timings);
3066
3067 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3068 info->training.timing_bounds[0][channel][slot][rank][lane].
3069 smallest =
3070 timings[info->training.
3071 reg178_smallest][channel][slot][rank][lane].
3072 smallest;
3073 info->training.timing_bounds[0][channel][slot][rank][lane].
3074 largest =
3075 timings[info->training.
3076 reg178_smallest][channel][slot][rank][lane].largest;
3077 info->training.timing_bounds[1][channel][slot][rank][lane].
3078 smallest =
3079 timings[info->training.
3080 reg178_largest][channel][slot][rank][lane].smallest;
3081 info->training.timing_bounds[1][channel][slot][rank][lane].
3082 largest =
3083 timings[info->training.
3084 reg178_largest][channel][slot][rank][lane].largest;
3085 info->training.timing_offset[channel][slot][rank][lane] =
3086 info->training.lane_timings[1][channel][slot][rank][lane]
3087 -
3088 info->training.lane_timings[0][channel][slot][rank][lane] +
3089 64;
3090 }
3091
3092 if (info->silicon_revision == 1
3093 && (info->
3094 populated_ranks_mask[1] ^ (info->
3095 populated_ranks_mask[1] >> 2)) & 1) {
3096 int ranks_after_channel1;
3097
3098 totalrank = 0;
3099 for (reg_178 = reg178_center - 18;
3100 reg_178 <= reg178_center + 18; reg_178 += 18) {
3101 totalrank = 0;
3102 set_178(reg_178);
3103 for (slot = 0; slot < NUM_SLOTS; slot++)
3104 for (rank = 0; rank < NUM_RANKS; rank++) {
3105 if (info->
3106 populated_ranks[1][slot][rank]) {
3107 train_ram_at_178(info, 1, slot,
3108 rank,
3109 totalrank,
3110 reg_178, 0,
3111 niter,
3112 timings);
3113 totalrank++;
3114 }
3115 }
3116 }
3117 ranks_after_channel1 = totalrank;
3118
3119 for (reg_178 = reg178_center - 12;
3120 reg_178 <= reg178_center + 12; reg_178 += 12) {
3121 totalrank = ranks_after_channel1;
3122 set_178(reg_178);
3123 for (slot = 0; slot < NUM_SLOTS; slot++)
3124 for (rank = 0; rank < NUM_RANKS; rank++)
3125 if (info->
3126 populated_ranks[0][slot][rank]) {
3127 train_ram_at_178(info, 0, slot,
3128 rank,
3129 totalrank,
3130 reg_178, 0,
3131 niter,
3132 timings);
3133 totalrank++;
3134 }
3135
3136 }
3137 } else {
3138 for (reg_178 = reg178_center - 12;
3139 reg_178 <= reg178_center + 12; reg_178 += 12) {
3140 totalrank = 0;
3141 set_178(reg_178);
3142 FOR_POPULATED_RANKS_BACKWARDS {
3143 train_ram_at_178(info, channel, slot, rank,
3144 totalrank, reg_178, 0, niter,
3145 timings);
3146 totalrank++;
3147 }
3148 }
3149 }
3150
3151 set_178(reg178_center);
3152 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3153 u16 tm0;
3154
3155 tm0 =
3156 choose_training(info, channel, slot, rank, lane, timings,
3157 reg178_center);
3158 write_500(info, channel, tm0,
3159 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3160 write_500(info, channel,
3161 tm0 +
3162 info->training.
3163 lane_timings[1][channel][slot][rank][lane] -
3164 info->training.
3165 lane_timings[0][channel][slot][rank][lane],
3166 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3167 }
3168
3169 totalrank = 0;
3170 FOR_POPULATED_RANKS_BACKWARDS {
3171 try_timing_offsets(info, channel, slot, rank, totalrank);
3172 totalrank++;
3173 }
Felix Held04be2dd2018-07-29 04:53:22 +02003174 MCHBAR8(0x243) = saved_243[0];
3175 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003176 write_1d0(0, 0x142, 3, 1);
3177 info->training.reg178_center = reg178_center;
3178}
3179
3180static void ram_training(struct raminfo *info)
3181{
3182 u16 saved_fc4;
3183
Felix Held04be2dd2018-07-29 04:53:22 +02003184 saved_fc4 = MCHBAR16(0xfc4);
3185 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003186
3187 if (info->revision >= 8)
3188 read_4090(info);
3189
3190 if (!try_cached_training(info))
3191 do_ram_training(info);
3192 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3193 && info->clock_speed_index < 2)
3194 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003195 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003196}
3197
Martin Roth468d02c2019-10-23 21:44:42 -06003198static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003199{
Martin Roth468d02c2019-10-23 21:44:42 -06003200 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003201 if (a > b) {
3202 t = a;
3203 a = b;
3204 b = t;
3205 }
3206 /* invariant a < b. */
3207 while (a) {
3208 t = b % a;
3209 b = a;
3210 a = t;
3211 }
3212 return b;
3213}
3214
3215static inline int div_roundup(int a, int b)
3216{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003217 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003218}
3219
Martin Roth468d02c2019-10-23 21:44:42 -06003220static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003221{
3222 return (a * b) / gcd(a, b);
3223}
3224
3225struct stru1 {
3226 u8 freqs_reversed;
3227 u8 freq_diff_reduced;
3228 u8 freq_min_reduced;
3229 u8 divisor_f4_to_fmax;
3230 u8 divisor_f3_to_fmax;
3231 u8 freq4_to_max_remainder;
3232 u8 freq3_to_2_remainder;
3233 u8 freq3_to_2_remaindera;
3234 u8 freq4_to_2_remainder;
3235 int divisor_f3_to_f1, divisor_f4_to_f2;
3236 int common_time_unit_ps;
3237 int freq_max_reduced;
3238};
3239
3240static void
3241compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3242 int num_cycles_2, int num_cycles_1, int round_it,
3243 int add_freqs, struct stru1 *result)
3244{
3245 int g;
3246 int common_time_unit_ps;
3247 int freq1_reduced, freq2_reduced;
3248 int freq_min_reduced;
3249 int freq_max_reduced;
3250 int freq3, freq4;
3251
3252 g = gcd(freq1, freq2);
3253 freq1_reduced = freq1 / g;
3254 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003255 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3256 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003257
3258 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3259 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3260 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3261 if (add_freqs) {
3262 freq3 += freq2_reduced;
3263 freq4 += freq1_reduced;
3264 }
3265
3266 if (round_it) {
3267 result->freq3_to_2_remainder = 0;
3268 result->freq3_to_2_remaindera = 0;
3269 result->freq4_to_max_remainder = 0;
3270 result->divisor_f4_to_f2 = 0;
3271 result->divisor_f3_to_f1 = 0;
3272 } else {
3273 if (freq2_reduced < freq1_reduced) {
3274 result->freq3_to_2_remainder =
3275 result->freq3_to_2_remaindera =
3276 freq3 % freq1_reduced - freq1_reduced + 1;
3277 result->freq4_to_max_remainder =
3278 -(freq4 % freq1_reduced);
3279 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3280 result->divisor_f4_to_f2 =
3281 (freq4 -
3282 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3283 result->freq4_to_2_remainder =
3284 -(char)((freq1_reduced - freq2_reduced) +
3285 ((u8) freq4 -
3286 (freq1_reduced -
3287 freq2_reduced)) % (u8) freq2_reduced);
3288 } else {
3289 if (freq2_reduced > freq1_reduced) {
3290 result->freq4_to_max_remainder =
3291 (freq4 % freq2_reduced) - freq2_reduced + 1;
3292 result->freq4_to_2_remainder =
3293 freq4 % freq_max_reduced -
3294 freq_max_reduced + 1;
3295 } else {
3296 result->freq4_to_max_remainder =
3297 -(freq4 % freq2_reduced);
3298 result->freq4_to_2_remainder =
3299 -(char)(freq4 % freq_max_reduced);
3300 }
3301 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3302 result->divisor_f3_to_f1 =
3303 (freq3 -
3304 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3305 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3306 result->freq3_to_2_remaindera =
3307 -(char)((freq_max_reduced - freq_min_reduced) +
3308 (freq3 -
3309 (freq_max_reduced -
3310 freq_min_reduced)) % freq1_reduced);
3311 }
3312 }
3313 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3314 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3315 if (round_it) {
3316 if (freq2_reduced > freq1_reduced) {
3317 if (freq3 % freq_max_reduced)
3318 result->divisor_f3_to_fmax++;
3319 }
3320 if (freq2_reduced < freq1_reduced) {
3321 if (freq4 % freq_max_reduced)
3322 result->divisor_f4_to_fmax++;
3323 }
3324 }
3325 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3326 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3327 result->freq_min_reduced = freq_min_reduced;
3328 result->common_time_unit_ps = common_time_unit_ps;
3329 result->freq_max_reduced = freq_max_reduced;
3330}
3331
3332static void
3333set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3334 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3335 int num_cycles_4, int reverse)
3336{
3337 struct stru1 vv;
3338 char multiplier;
3339
3340 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3341 0, 1, &vv);
3342
3343 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003344 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003345 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3346 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3347 div_roundup(num_cycles_1,
3348 vv.common_time_unit_ps) +
3349 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3350 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3351
3352 u32 y =
3353 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3354 vv.freq_max_reduced * multiplier)
3355 | (vv.
3356 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3357 multiplier) << 16) | ((u8) (vv.
3358 freq_min_reduced
3359 *
3360 multiplier)
3361 << 24);
3362 u32 x =
3363 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3364 divisor_f3_to_f1
3365 << 16)
3366 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3367 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003368 MCHBAR32(reg) = y;
3369 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003370 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003371 MCHBAR32(reg + 4) = y;
3372 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003373 }
3374}
3375
3376static void
3377set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3378 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3379 int num_cycles_4)
3380{
3381 struct stru1 ratios1;
3382 struct stru1 ratios2;
3383
3384 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3385 0, 1, &ratios2);
3386 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3387 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003388 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003389 ratios1.freq4_to_max_remainder | (ratios2.
3390 freq4_to_max_remainder
3391 << 8)
3392 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3393 divisor_f4_to_fmax
3394 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003395 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3396 (ratios2.freq4_to_max_remainder << 8) |
3397 (ratios1.divisor_f4_to_fmax << 16) |
3398 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003399}
3400
3401static void
3402set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3403 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3404{
3405 struct stru1 ratios;
3406
3407 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3408 round_it, add_freqs, &ratios);
3409 switch (mode) {
3410 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003411 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3412 (ratios.freqs_reversed << 8);
3413 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3414 (ratios.freq4_to_max_remainder << 8) |
3415 (ratios.divisor_f3_to_fmax << 16) |
3416 (ratios.divisor_f4_to_fmax << 20) |
3417 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003418 break;
3419
3420 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003421 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3422 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003423 break;
3424
3425 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003426 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3427 (ratios.freq4_to_max_remainder << 8) |
3428 (ratios.divisor_f3_to_fmax << 16) |
3429 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003430 break;
3431
3432 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003433 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3434 (ratios.divisor_f4_to_fmax << 8) |
3435 (ratios.freqs_reversed << 12) |
3436 (ratios.freq_min_reduced << 16) |
3437 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003438 break;
3439 }
3440}
3441
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003442static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003443{
3444 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3445 0, 1);
3446 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3447 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3448 1);
3449 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3450 frequency_11(info), 1231, 1524, 0, 1);
3451 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3452 frequency_11(info) / 2, 1278, 2008, 0, 1);
3453 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3454 1167, 1539, 0, 1);
3455 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3456 frequency_11(info) / 2, 1403, 1318, 0, 1);
3457 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3458 1);
3459 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3460 1);
3461 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3462 1, 1);
3463 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3464 1);
3465 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3466 frequency_11(info) / 2, 4000, 0, 0, 0);
3467 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3468 frequency_11(info) / 2, 4000, 4000, 0, 0);
3469
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003470 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003471 printk(RAM_SPEW, "[6dc] <= %x\n",
3472 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003473 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003474 } else
3475 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3476 info->delay46_ps[0], 0,
3477 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003478 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3479 frequency_11(info), 2500, 0, 0, 0);
3480 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3481 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003482 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003483 printk(RAM_SPEW, "[6e8] <= %x\n",
3484 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003485 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003486 } else
3487 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3488 info->delay46_ps[1], 0,
3489 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003490 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3491 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3492 470, 0);
3493 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3494 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3495 454, 459, 0);
3496 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3497 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3498 2588, 0);
3499 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3500 2405, 0);
3501 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3502 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3503 480, 0);
3504 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003505 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3506 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003507}
3508
3509static u16 get_max_timing(struct raminfo *info, int channel)
3510{
3511 int slot, rank, lane;
3512 u16 ret = 0;
3513
Felix Held04be2dd2018-07-29 04:53:22 +02003514 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003515 return 384;
3516
3517 if (info->revision < 8)
3518 return 256;
3519
3520 for (slot = 0; slot < NUM_SLOTS; slot++)
3521 for (rank = 0; rank < NUM_RANKS; rank++)
3522 if (info->populated_ranks[channel][slot][rank])
3523 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003524 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003525 get_timing_register_addr
3526 (lane, 0, slot,
3527 rank), 9));
3528 return ret;
3529}
3530
3531static void set_274265(struct raminfo *info)
3532{
3533 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3534 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3535 int delay_e_over_cycle_ps;
3536 int cycletime_ps;
3537 int channel;
3538
3539 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003540 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003541 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3542 cycletime_ps =
3543 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3544 delay_d_ps =
3545 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3546 - info->some_delay_3_ps_rounded + 200;
3547 if (!
3548 ((info->silicon_revision == 0
3549 || info->silicon_revision == 1)
3550 && (info->revision >= 8)))
3551 delay_d_ps += halfcycle_ps(info) * 2;
3552 delay_d_ps +=
3553 halfcycle_ps(info) * (!info->revision_flag_1 +
3554 info->some_delay_2_halfcycles_ceil +
3555 2 * info->some_delay_1_cycle_floor +
3556 info->clock_speed_index +
3557 2 * info->cas_latency - 7 + 11);
3558 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3559
Felix Held04be2dd2018-07-29 04:53:22 +02003560 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3561 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3562 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003563 delay_d_ps += 650;
3564 delay_c_ps = delay_d_ps + 1800;
3565 if (delay_c_ps <= delay_a_ps)
3566 delay_e_ps = 0;
3567 else
3568 delay_e_ps =
3569 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3570 cycletime_ps);
3571
3572 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3573 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3574 delay_f_cycles =
3575 div_roundup(2500 - delay_e_over_cycle_ps,
3576 2 * halfcycle_ps(info));
3577 if (delay_f_cycles > delay_e_cycles) {
3578 info->delay46_ps[channel] = delay_e_ps;
3579 delay_e_cycles = 0;
3580 } else {
3581 info->delay46_ps[channel] =
3582 delay_e_over_cycle_ps +
3583 2 * halfcycle_ps(info) * delay_f_cycles;
3584 delay_e_cycles -= delay_f_cycles;
3585 }
3586
3587 if (info->delay46_ps[channel] < 2500) {
3588 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003589 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003590 }
3591 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3592 if (delay_b_ps <= delay_a_ps)
3593 delay_b_ps = 0;
3594 else
3595 delay_b_ps -= delay_a_ps;
3596 info->delay54_ps[channel] =
3597 cycletime_ps * div_roundup(delay_b_ps,
3598 cycletime_ps) -
3599 2 * halfcycle_ps(info) * delay_e_cycles;
3600 if (info->delay54_ps[channel] < 2500)
3601 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003602 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3604 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003605 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003606 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003607 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003608 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3609 4 * halfcycle_ps(info)) - 6;
3610 MCHBAR32((channel << 10) + 0x274) =
3611 info->training.reg274265[channel][1] |
3612 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003613 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003614 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3615 4 * halfcycle_ps(info)) + 1;
3616 MCHBAR16((channel << 10) + 0x265) =
3617 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003619 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003620 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621 else
Felix Held04be2dd2018-07-29 04:53:22 +02003622 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623}
3624
3625static void restore_274265(struct raminfo *info)
3626{
3627 int channel;
3628
3629 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003630 MCHBAR32((channel << 10) + 0x274) =
3631 (info->cached_training->reg274265[channel][0] << 16) |
3632 info->cached_training->reg274265[channel][1];
3633 MCHBAR16((channel << 10) + 0x265) =
3634 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003636 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003637 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638 else
Felix Held04be2dd2018-07-29 04:53:22 +02003639 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640}
3641
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642static void dmi_setup(void)
3643{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003644 gav(read8(DEFAULT_DMIBAR + 0x254));
3645 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3646 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003647 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003649 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
3651 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3652 DEFAULT_GPIOBASE | 0x38);
3653 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3654}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003656void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003658 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003659 u16 ggc;
3660 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661
Felix Held04be2dd2018-07-29 04:53:22 +02003662 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3664 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003665 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003666 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667 }
Felix Held29a9c072018-07-29 01:34:45 +02003668#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669 if (!s3resume) {
3670 pre_raminit_3(x2ca8);
3671 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003672 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673#endif
3674
3675 dmi_setup();
3676
Felix Held04be2dd2018-07-29 04:53:22 +02003677 MCHBAR16(0x1170) = 0xa880;
3678 MCHBAR8(0x11c1) = 0x1;
3679 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003680 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003681
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003682 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3683 /* 0 for 32MB */
3684 gfxsize = 0;
3685 }
3686
3687 ggc = 0xb00 | ((gfxsize + 5) << 4);
3688
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003689 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690
3691 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003692 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003693
3694 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003695 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003696 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003697 MCHBAR16_OR(0x2c30, 0x200);
3698 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003699 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003700 pci_read_config8(GMA, 0x62); // = 0x2
3701 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003702 read8(DEFAULT_RCBA + 0x2318);
3703 write8(DEFAULT_RCBA + 0x2318, 0x47);
3704 read8(DEFAULT_RCBA + 0x2320);
3705 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706 }
3707
Felix Heldf83d80b2018-07-29 05:30:30 +02003708 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003709
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003710 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003711 gav(read32(DEFAULT_RCBA + 0x3428));
3712 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003713}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003714
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003715void raminit(const int s3resume, const u8 *spd_addrmap)
3716{
Martin Roth468d02c2019-10-23 21:44:42 -06003717 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003718 int i;
3719 struct raminfo info;
3720 u8 x2ca8;
3721 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003722 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003723
Felix Held04be2dd2018-07-29 04:53:22 +02003724 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003725
3726 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3727
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003728 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003729
3730 memset(&info, 0x5a, sizeof(info));
3731
3732 info.last_500_command[0] = 0;
3733 info.last_500_command[1] = 0;
3734
3735 info.fsb_frequency = 135 * 2;
3736 info.board_lane_delay[0] = 0x14;
3737 info.board_lane_delay[1] = 0x07;
3738 info.board_lane_delay[2] = 0x07;
3739 info.board_lane_delay[3] = 0x08;
3740 info.board_lane_delay[4] = 0x56;
3741 info.board_lane_delay[5] = 0x04;
3742 info.board_lane_delay[6] = 0x04;
3743 info.board_lane_delay[7] = 0x05;
3744 info.board_lane_delay[8] = 0x10;
3745
3746 info.training.reg_178 = 0;
3747 info.training.reg_10b = 0;
3748
3749 info.heci_bar = 0;
3750 info.memory_reserved_for_heci_mb = 0;
3751
3752 /* before SPD */
3753 timestamp_add_now(101);
3754
Felix Held29a9c072018-07-29 01:34:45 +02003755 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003756 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003757
3758 collect_system_info(&info);
3759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003760 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3761
3762 info.use_ecc = 1;
3763 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003764 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765 int v;
3766 int try;
3767 int addr;
3768 const u8 useful_addresses[] = {
3769 DEVICE_TYPE,
3770 MODULE_TYPE,
3771 DENSITY,
3772 RANKS_AND_DQ,
3773 MEMORY_BUS_WIDTH,
3774 TIMEBASE_DIVIDEND,
3775 TIMEBASE_DIVISOR,
3776 CYCLETIME,
3777 CAS_LATENCIES_LSB,
3778 CAS_LATENCIES_MSB,
3779 CAS_LATENCY_TIME,
3780 0x11, 0x12, 0x13, 0x14, 0x15,
3781 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3782 0x1c, 0x1d,
3783 THERMAL_AND_REFRESH,
3784 0x20,
3785 REFERENCE_RAW_CARD_USED,
3786 RANK1_ADDRESS_MAPPING,
3787 0x75, 0x76, 0x77, 0x78,
3788 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3789 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3790 0x85, 0x86, 0x87, 0x88,
3791 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3792 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3793 0x95
3794 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003795 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003796 continue;
3797 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003798 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003799 DEVICE_TYPE);
3800 if (v >= 0)
3801 break;
3802 }
3803 if (v < 0)
3804 continue;
3805 for (addr = 0;
3806 addr <
3807 sizeof(useful_addresses) /
3808 sizeof(useful_addresses[0]); addr++)
3809 gav(info.
3810 spd[channel][0][useful_addresses
3811 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003812 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003813 useful_addresses
3814 [addr]));
3815 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3816 die("Only DDR3 is supported");
3817
3818 v = info.spd[channel][0][RANKS_AND_DQ];
3819 info.populated_ranks[channel][0][0] = 1;
3820 info.populated_ranks[channel][0][1] =
3821 ((v >> 3) & 7);
3822 if (((v >> 3) & 7) > 1)
3823 die("At most 2 ranks are supported");
3824 if ((v & 7) == 0 || (v & 7) > 2)
3825 die("Only x8 and x16 modules are supported");
3826 if ((info.
3827 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3828 && (info.
3829 spd[channel][slot][MODULE_TYPE] & 0xF)
3830 != 3)
3831 die("Registered memory is not supported");
3832 info.is_x16_module[channel][0] = (v & 7) - 1;
3833 info.density[channel][slot] =
3834 info.spd[channel][slot][DENSITY] & 0xF;
3835 if (!
3836 (info.
3837 spd[channel][slot][MEMORY_BUS_WIDTH] &
3838 0x18))
3839 info.use_ecc = 0;
3840 }
3841
3842 gav(0x55);
3843
3844 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3845 int v = 0;
3846 for (slot = 0; slot < NUM_SLOTS; slot++)
3847 for (rank = 0; rank < NUM_RANKS; rank++)
3848 v |= info.
3849 populated_ranks[channel][slot][rank]
3850 << (2 * slot + rank);
3851 info.populated_ranks_mask[channel] = v;
3852 }
3853
3854 gav(0x55);
3855
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003856 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003857 }
3858
3859 /* after SPD */
3860 timestamp_add_now(102);
3861
Felix Held04be2dd2018-07-29 04:53:22 +02003862 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863
3864 collect_system_info(&info);
3865 calculate_timings(&info);
3866
Felix Held29a9c072018-07-29 01:34:45 +02003867#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003868 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869#endif
3870
3871 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003872 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003873 if (x2ca8 == 0 && (reg8 & 0x80)) {
3874 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3875 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3876 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3877 */
3878
3879 /* Clear bit7. */
3880
3881 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3882 (reg8 & ~(1 << 7)));
3883
3884 printk(BIOS_INFO,
3885 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003886 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887 }
3888 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889
3890 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003891 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3892 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893
3894 compute_derived_timings(&info);
3895
3896 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003897 gav(MCHBAR8(0x164));
3898 MCHBAR8(0x164) = 0x26;
3899 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900 }
3901
Felix Held04be2dd2018-07-29 04:53:22 +02003902 MCHBAR32_OR(0x18b4, 0x210000);
3903 MCHBAR32_OR(0x1890, 0x2000000);
3904 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003906 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3907 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003908
Felix Held04be2dd2018-07-29 04:53:22 +02003909 gav(MCHBAR16(0x2c10));
3910 MCHBAR16(0x2c10) = 0x412;
3911 gav(MCHBAR16(0x2c10));
3912 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 gav(MCHBAR8(0x2ca8)); // !!!!
3915 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003917 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3918 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003919 gav(MCHBAR32(0x1c04)); // !!!!
3920 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921
3922 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003923 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003924 }
3925
Felix Held04be2dd2018-07-29 04:53:22 +02003926 MCHBAR32(0x18d8) = 0x120000;
3927 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003928 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3929 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003930 MCHBAR32(0x18d8) = 0x40000;
3931 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003932 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3933 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003934 MCHBAR32(0x18d8) = 0x180000;
3935 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003936 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3937 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003938 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003939
Felix Held04be2dd2018-07-29 04:53:22 +02003940 gav(MCHBAR32(0x18dc)); // !!!!
3941 MCHBAR32(0x18dc) = 0x3;
3942 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943
3944 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003945 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003946 }
3947
Felix Held04be2dd2018-07-29 04:53:22 +02003948 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003949 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003950 MCHBAR32(0x1a10) = 0x4200010e;
3951 MCHBAR32_OR(0x18b8, 0x200);
3952 gav(MCHBAR32(0x1918)); // !!!!
3953 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954
Felix Held04be2dd2018-07-29 04:53:22 +02003955 gav(MCHBAR32(0x18b8)); // !!!!
3956 MCHBAR32(0x18b8) = 0xe00;
3957 gav(MCHBAR32(0x182c)); // !!!!
3958 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003959 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3960 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003961 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3962 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003963
Felix Held04be2dd2018-07-29 04:53:22 +02003964 MCHBAR32_AND(0x18b4, 0xffff7fff);
3965 gav(MCHBAR32(0x1a68)); // !!!!
3966 MCHBAR32(0x1a68) = 0x343800;
3967 gav(MCHBAR32(0x1e68)); // !!!!
3968 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003969
3970 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003971 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003972 }
3973
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003974 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3975 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3976 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3977 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3978 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3979 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3980 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003981 gav(MCHBAR32(0x1af0)); // !!!!
3982 gav(MCHBAR32(0x1af0)); // !!!!
3983 MCHBAR32(0x1af0) = 0x1f020003;
3984 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003985
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003986 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003987 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003988 }
3989
Felix Held04be2dd2018-07-29 04:53:22 +02003990 gav(MCHBAR32(0x1890)); // !!!!
3991 MCHBAR32(0x1890) = 0x80102;
3992 gav(MCHBAR32(0x18b4)); // !!!!
3993 MCHBAR32(0x18b4) = 0x216000;
3994 MCHBAR32(0x18a4) = 0x22222222;
3995 MCHBAR32(0x18a8) = 0x22222222;
3996 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003997
3998 udelay(1000);
3999
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004000 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004001
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004002 if (x2ca8 == 0) {
4003 int j;
4004 if (s3resume && info.cached_training) {
4005 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004006 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004007 info.cached_training->reg2ca9_bit0);
4008 for (i = 0; i < 2; i++)
4009 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004010 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004011 i, j, info.cached_training->reg274265[i][j]);
4012 } else {
4013 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004014 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004015 info.training.reg2ca9_bit0);
4016 for (i = 0; i < 2; i++)
4017 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004018 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004019 i, j, info.training.reg274265[i][j]);
4020 }
4021
4022 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004023
4024 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004025 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004026 }
4027
4028 udelay(1000);
4029
4030 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004031 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004032 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004033 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4034 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4035 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004036
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004037 MCHBAR8(0x1150);
4038 MCHBAR8(0x1151);
4039 MCHBAR8(0x1022);
4040 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004041 MCHBAR32(0x1300) = 0x60606060;
4042 MCHBAR32(0x1304) = 0x60606060;
4043 MCHBAR32(0x1308) = 0x78797a7b;
4044 MCHBAR32(0x130c) = 0x7c7d7e7f;
4045 MCHBAR32(0x1310) = 0x60606060;
4046 MCHBAR32(0x1314) = 0x60606060;
4047 MCHBAR32(0x1318) = 0x60606060;
4048 MCHBAR32(0x131c) = 0x60606060;
4049 MCHBAR32(0x1320) = 0x50515253;
4050 MCHBAR32(0x1324) = 0x54555657;
4051 MCHBAR32(0x1328) = 0x58595a5b;
4052 MCHBAR32(0x132c) = 0x5c5d5e5f;
4053 MCHBAR32(0x1330) = 0x40414243;
4054 MCHBAR32(0x1334) = 0x44454647;
4055 MCHBAR32(0x1338) = 0x48494a4b;
4056 MCHBAR32(0x133c) = 0x4c4d4e4f;
4057 MCHBAR32(0x1340) = 0x30313233;
4058 MCHBAR32(0x1344) = 0x34353637;
4059 MCHBAR32(0x1348) = 0x38393a3b;
4060 MCHBAR32(0x134c) = 0x3c3d3e3f;
4061 MCHBAR32(0x1350) = 0x20212223;
4062 MCHBAR32(0x1354) = 0x24252627;
4063 MCHBAR32(0x1358) = 0x28292a2b;
4064 MCHBAR32(0x135c) = 0x2c2d2e2f;
4065 MCHBAR32(0x1360) = 0x10111213;
4066 MCHBAR32(0x1364) = 0x14151617;
4067 MCHBAR32(0x1368) = 0x18191a1b;
4068 MCHBAR32(0x136c) = 0x1c1d1e1f;
4069 MCHBAR32(0x1370) = 0x10203;
4070 MCHBAR32(0x1374) = 0x4050607;
4071 MCHBAR32(0x1378) = 0x8090a0b;
4072 MCHBAR32(0x137c) = 0xc0d0e0f;
4073 MCHBAR8(0x11cc) = 0x4e;
4074 MCHBAR32(0x1110) = 0x73970404;
4075 MCHBAR32(0x1114) = 0x72960404;
4076 MCHBAR32(0x1118) = 0x6f950404;
4077 MCHBAR32(0x111c) = 0x6d940404;
4078 MCHBAR32(0x1120) = 0x6a930404;
4079 MCHBAR32(0x1124) = 0x68a41404;
4080 MCHBAR32(0x1128) = 0x66a21404;
4081 MCHBAR32(0x112c) = 0x63a01404;
4082 MCHBAR32(0x1130) = 0x609e1404;
4083 MCHBAR32(0x1134) = 0x5f9c1404;
4084 MCHBAR32(0x1138) = 0x5c961404;
4085 MCHBAR32(0x113c) = 0x58a02404;
4086 MCHBAR32(0x1140) = 0x54942404;
4087 MCHBAR32(0x1190) = 0x900080a;
4088 MCHBAR16(0x11c0) = 0xc40b;
4089 MCHBAR16(0x11c2) = 0x303;
4090 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004091 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004092 MCHBAR32(0x11b8) = 0x70c3000;
4093 MCHBAR8(0x11ec) = 0xa;
4094 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004095 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004096 MCHBAR16(0x11ca) = 0xfa;
4097 MCHBAR32(0x11e4) = 0x4e20;
4098 MCHBAR8(0x11bc) = 0xf;
4099 MCHBAR16(0x11da) = 0x19;
4100 MCHBAR16(0x11ba) = 0x470c;
4101 MCHBAR32(0x1680) = 0xe6ffe4ff;
4102 MCHBAR32(0x1684) = 0xdeffdaff;
4103 MCHBAR32(0x1688) = 0xd4ffd0ff;
4104 MCHBAR32(0x168c) = 0xccffc6ff;
4105 MCHBAR32(0x1690) = 0xc0ffbeff;
4106 MCHBAR32(0x1694) = 0xb8ffb0ff;
4107 MCHBAR32(0x1698) = 0xa8ff0000;
4108 MCHBAR32(0x169c) = 0xc00;
4109 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004110 }
4111
Felix Held04be2dd2018-07-29 04:53:22 +02004112 MCHBAR32(0x124c) = 0x15040d00;
4113 MCHBAR32(0x1250) = 0x7f0000;
4114 MCHBAR32(0x1254) = 0x1e220004;
4115 MCHBAR32(0x1258) = 0x4000004;
4116 MCHBAR32(0x1278) = 0x0;
4117 MCHBAR32(0x125c) = 0x0;
4118 MCHBAR32(0x1260) = 0x0;
4119 MCHBAR32(0x1264) = 0x0;
4120 MCHBAR32(0x1268) = 0x0;
4121 MCHBAR32(0x126c) = 0x0;
4122 MCHBAR32(0x1270) = 0x0;
4123 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004124 }
4125
4126 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004127 MCHBAR16(0x1214) = 0x320;
4128 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004129 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4130 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004131 MCHBAR32(0x1400) = 0x13040020;
4132 MCHBAR32(0x1404) = 0xe090120;
4133 MCHBAR32(0x1408) = 0x5120220;
4134 MCHBAR32(0x140c) = 0x5120330;
4135 MCHBAR32(0x1410) = 0xe090220;
4136 MCHBAR32(0x1414) = 0x1010001;
4137 MCHBAR32(0x1418) = 0x1110000;
4138 MCHBAR32(0x141c) = 0x9020020;
4139 MCHBAR32(0x1420) = 0xd090220;
4140 MCHBAR32(0x1424) = 0x2090220;
4141 MCHBAR32(0x1428) = 0x2090330;
4142 MCHBAR32(0x142c) = 0xd090220;
4143 MCHBAR32(0x1430) = 0x1010001;
4144 MCHBAR32(0x1434) = 0x1110000;
4145 MCHBAR32(0x1438) = 0x11040020;
4146 MCHBAR32(0x143c) = 0x4030220;
4147 MCHBAR32(0x1440) = 0x1060220;
4148 MCHBAR32(0x1444) = 0x1060330;
4149 MCHBAR32(0x1448) = 0x4030220;
4150 MCHBAR32(0x144c) = 0x1010001;
4151 MCHBAR32(0x1450) = 0x1110000;
4152 MCHBAR32(0x1454) = 0x4010020;
4153 MCHBAR32(0x1458) = 0xb090220;
4154 MCHBAR32(0x145c) = 0x1090220;
4155 MCHBAR32(0x1460) = 0x1090330;
4156 MCHBAR32(0x1464) = 0xb090220;
4157 MCHBAR32(0x1468) = 0x1010001;
4158 MCHBAR32(0x146c) = 0x1110000;
4159 MCHBAR32(0x1470) = 0xf040020;
4160 MCHBAR32(0x1474) = 0xa090220;
4161 MCHBAR32(0x1478) = 0x1120220;
4162 MCHBAR32(0x147c) = 0x1120330;
4163 MCHBAR32(0x1480) = 0xa090220;
4164 MCHBAR32(0x1484) = 0x1010001;
4165 MCHBAR32(0x1488) = 0x1110000;
4166 MCHBAR32(0x148c) = 0x7020020;
4167 MCHBAR32(0x1490) = 0x1010220;
4168 MCHBAR32(0x1494) = 0x10210;
4169 MCHBAR32(0x1498) = 0x10320;
4170 MCHBAR32(0x149c) = 0x1010220;
4171 MCHBAR32(0x14a0) = 0x1010001;
4172 MCHBAR32(0x14a4) = 0x1110000;
4173 MCHBAR32(0x14a8) = 0xd040020;
4174 MCHBAR32(0x14ac) = 0x8090220;
4175 MCHBAR32(0x14b0) = 0x1111310;
4176 MCHBAR32(0x14b4) = 0x1111420;
4177 MCHBAR32(0x14b8) = 0x8090220;
4178 MCHBAR32(0x14bc) = 0x1010001;
4179 MCHBAR32(0x14c0) = 0x1110000;
4180 MCHBAR32(0x14c4) = 0x3010020;
4181 MCHBAR32(0x14c8) = 0x7090220;
4182 MCHBAR32(0x14cc) = 0x1081310;
4183 MCHBAR32(0x14d0) = 0x1081420;
4184 MCHBAR32(0x14d4) = 0x7090220;
4185 MCHBAR32(0x14d8) = 0x1010001;
4186 MCHBAR32(0x14dc) = 0x1110000;
4187 MCHBAR32(0x14e0) = 0xb040020;
4188 MCHBAR32(0x14e4) = 0x2030220;
4189 MCHBAR32(0x14e8) = 0x1051310;
4190 MCHBAR32(0x14ec) = 0x1051420;
4191 MCHBAR32(0x14f0) = 0x2030220;
4192 MCHBAR32(0x14f4) = 0x1010001;
4193 MCHBAR32(0x14f8) = 0x1110000;
4194 MCHBAR32(0x14fc) = 0x5020020;
4195 MCHBAR32(0x1500) = 0x5090220;
4196 MCHBAR32(0x1504) = 0x2071310;
4197 MCHBAR32(0x1508) = 0x2071420;
4198 MCHBAR32(0x150c) = 0x5090220;
4199 MCHBAR32(0x1510) = 0x1010001;
4200 MCHBAR32(0x1514) = 0x1110000;
4201 MCHBAR32(0x1518) = 0x7040120;
4202 MCHBAR32(0x151c) = 0x2090220;
4203 MCHBAR32(0x1520) = 0x70b1210;
4204 MCHBAR32(0x1524) = 0x70b1310;
4205 MCHBAR32(0x1528) = 0x2090220;
4206 MCHBAR32(0x152c) = 0x1010001;
4207 MCHBAR32(0x1530) = 0x1110000;
4208 MCHBAR32(0x1534) = 0x1010110;
4209 MCHBAR32(0x1538) = 0x1081310;
4210 MCHBAR32(0x153c) = 0x5041200;
4211 MCHBAR32(0x1540) = 0x5041310;
4212 MCHBAR32(0x1544) = 0x1081310;
4213 MCHBAR32(0x1548) = 0x1010001;
4214 MCHBAR32(0x154c) = 0x1110000;
4215 MCHBAR32(0x1550) = 0x1040120;
4216 MCHBAR32(0x1554) = 0x4051210;
4217 MCHBAR32(0x1558) = 0xd051200;
4218 MCHBAR32(0x155c) = 0xd051200;
4219 MCHBAR32(0x1560) = 0x4051210;
4220 MCHBAR32(0x1564) = 0x1010001;
4221 MCHBAR32(0x1568) = 0x1110000;
4222 MCHBAR16(0x1222) = 0x220a;
4223 MCHBAR16(0x123c) = 0x1fc0;
4224 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004225 }
4226
Felix Heldf83d80b2018-07-29 05:30:30 +02004227 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004228 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004229 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004230
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004231 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004232
4233 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004234 MCHBAR8_AND(0x2ca8, ~3);
4235 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004236 /* This issues a CPU reset without resetting the platform */
4237 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004238 /* Write back the S3 state to PM1_CNT to let the reset CPU
4239 know it also needs to take the s3 path. */
4240 if (s3resume)
4241 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4242 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004243 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004244 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004245 }
4246
Felix Held04be2dd2018-07-29 04:53:22 +02004247 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004248 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004249 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004250 MCHBAR16(0x2c20); // !!!!
4251 MCHBAR16(0x2c10); // !!!!
4252 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254 udelay(1000);
4255 write_1d0(0, 0x33d, 0, 0);
4256 write_500(&info, 0, 0, 0xb61, 0, 0);
4257 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR32(0x1a30) = 0x0;
4259 MCHBAR32(0x1a34) = 0x0;
4260 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4261 (info.populated_ranks[0][0][0] * 0xa0);
4262 MCHBAR16(0x616) = 0x26a;
4263 MCHBAR32(0x134) = 0x856000;
4264 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004265 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4266 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004267 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004268 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4269 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004271 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004272 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4273 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004274 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4275 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4276 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4277 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4278 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4279 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4280 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4281 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4282 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4283 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004284 }
4285
4286 write_1d0(0x4, 0x151, 4, 1);
4287 write_1d0(0, 0x142, 3, 1);
4288 rdmsr(0x1ac); // !!!!
4289 write_500(&info, 1, 1, 0x6b3, 4, 1);
4290 write_500(&info, 1, 1, 0x6cf, 4, 1);
4291
4292 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4293
4294 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4295 populated_ranks[0]
4296 [0][0]) << 0),
4297 0x1d1, 3, 1);
4298 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004299 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4300 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004301 }
4302
4303 set_334(0);
4304
4305 program_base_timings(&info);
4306
Felix Held04be2dd2018-07-29 04:53:22 +02004307 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004308
4309 write_1d0(0x2, 0x1d5, 2, 1);
4310 write_1d0(0x20, 0x166, 7, 1);
4311 write_1d0(0x0, 0xeb, 3, 1);
4312 write_1d0(0x0, 0xf3, 6, 1);
4313
4314 for (channel = 0; channel < NUM_CHANNELS; channel++)
4315 for (lane = 0; lane < 9; lane++) {
4316 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4317 u8 a;
4318 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4319 write_500(&info, channel, a, addr, 6, 1);
4320 }
4321
4322 udelay(1000);
4323
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004324 if (s3resume) {
4325 if (info.cached_training == NULL) {
4326 u32 reg32;
4327 printk(BIOS_ERR,
4328 "Couldn't find training data. Rebooting\n");
4329 reg32 = inl(DEFAULT_PMBASE + 0x04);
4330 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004331 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004332 }
4333 int tm;
4334 info.training = *info.cached_training;
4335 for (tm = 0; tm < 4; tm++)
4336 for (channel = 0; channel < NUM_CHANNELS; channel++)
4337 for (slot = 0; slot < NUM_SLOTS; slot++)
4338 for (rank = 0; rank < NUM_RANKS; rank++)
4339 for (lane = 0; lane < 9; lane++)
4340 write_500(&info,
4341 channel,
4342 info.training.
4343 lane_timings
4344 [tm][channel]
4345 [slot][rank]
4346 [lane],
4347 get_timing_register_addr
4348 (lane, tm,
4349 slot, rank),
4350 9, 0);
4351 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4352 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4353 }
4354
Felix Heldf83d80b2018-07-29 05:30:30 +02004355 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004356 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004357 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004358 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004359
4360 program_board_delay(&info);
4361
Felix Held04be2dd2018-07-29 04:53:22 +02004362 MCHBAR8(0x5ff) = 0x0;
4363 MCHBAR8(0x5ff) = 0x80;
4364 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365
Felix Held04be2dd2018-07-29 04:53:22 +02004366 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004367 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004368 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004369 gav(read_1d0(0x14b, 7)); // = 0x81023100
4370 write_1d0(0x30, 0x14b, 7, 1);
4371 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4372 write_1d0(7, 0xd6, 6, 1);
4373 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4374 write_1d0(7, 0x328, 6, 1);
4375
4376 for (channel = 0; channel < NUM_CHANNELS; channel++)
4377 set_4cf(&info, channel,
4378 info.populated_ranks[channel][0][0] ? 8 : 0);
4379
4380 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4381 write_1d0(2, 0x116, 4, 1);
4382 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4383 write_1d0(0, 0xae, 6, 1);
4384 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4385 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004386 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4387 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004388 MCHBAR32_AND(0x140, ~0x07000000);
4389 MCHBAR32_AND(0x138, ~0x07000000);
4390 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004391 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004392 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004393 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004394
4395 {
4396 u32 t;
4397 u8 val_a1;
4398 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4399 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4400 rmw_1d0(0x320, 0x07,
4401 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4402 rmw_1d0(0x14b, 0x78,
4403 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4404 4), 7,
4405 1);
4406 rmw_1d0(0xce, 0x38,
4407 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4408 4), 6,
4409 1);
4410 }
4411
4412 for (channel = 0; channel < NUM_CHANNELS; channel++)
4413 set_4cf(&info, channel,
4414 info.populated_ranks[channel][0][0] ? 9 : 1);
4415
4416 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004417 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004418 write_1d0(2, 0xae, 6, 1);
4419 write_1d0(2, 0x300, 6, 1);
4420 write_1d0(2, 0x121, 3, 1);
4421 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4422 write_1d0(4, 0xd6, 6, 1);
4423 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4424 write_1d0(4, 0x328, 6, 1);
4425
4426 for (channel = 0; channel < NUM_CHANNELS; channel++)
4427 set_4cf(&info, channel,
4428 info.populated_ranks[channel][0][0] ? 9 : 0);
4429
Felix Held04be2dd2018-07-29 04:53:22 +02004430 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4431 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004432 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004433 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004434 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4435 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4436 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4437 write_1d0(0, 0x21c, 6, 1);
4438 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4439 write_1d0(0x35, 0x14b, 7, 1);
4440
4441 for (channel = 0; channel < NUM_CHANNELS; channel++)
4442 set_4cf(&info, channel,
4443 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4444
4445 set_334(1);
4446
Felix Held04be2dd2018-07-29 04:53:22 +02004447 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004448
4449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4450 write_500(&info, channel,
4451 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4452 1);
4453 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4454 }
Felix Held04be2dd2018-07-29 04:53:22 +02004455 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4456 MCHBAR16(0x6c0) = 0x14a0;
4457 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4458 MCHBAR16(0x232) = 0x8;
4459 /* 0x40004 or 0 depending on ? */
4460 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4461 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4462 MCHBAR32(0x128) = 0x2150d05;
4463 MCHBAR8(0x12c) = 0x1f;
4464 MCHBAR8(0x12d) = 0x56;
4465 MCHBAR8(0x12e) = 0x31;
4466 MCHBAR8(0x12f) = 0x0;
4467 MCHBAR8(0x271) = 0x2;
4468 MCHBAR8(0x671) = 0x2;
4469 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004470 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004471 MCHBAR32(0x294 + (channel << 10)) =
4472 (info.populated_ranks_mask[channel] & 3) << 16;
4473 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4474 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004476 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4477 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004478
4479 if (!s3resume)
4480 jedec_init(&info);
4481
4482 int totalrank = 0;
4483 for (channel = 0; channel < NUM_CHANNELS; channel++)
4484 for (slot = 0; slot < NUM_SLOTS; slot++)
4485 for (rank = 0; rank < NUM_RANKS; rank++)
4486 if (info.populated_ranks[channel][slot][rank]) {
4487 jedec_read(&info, channel, slot, rank,
4488 totalrank, 0xa, 0x400);
4489 totalrank++;
4490 }
4491
Felix Held04be2dd2018-07-29 04:53:22 +02004492 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493
Felix Heldf83d80b2018-07-29 05:30:30 +02004494 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4495 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004496
4497 if (!s3resume) {
4498 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004499 MCHBAR32(0x294 + (channel << 10)) =
4500 (info.populated_ranks_mask[channel] & 3) << 16;
4501 MCHBAR16(0x298 + (channel << 10)) =
4502 info.populated_ranks[channel][0][0] |
4503 (info.populated_ranks[channel][0][1] << 5);
4504 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004506 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004507
4508 {
4509 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004510 a = MCHBAR8(0x243);
4511 b = MCHBAR8(0x643);
4512 MCHBAR8(0x243) = a | 2;
4513 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004514 }
4515
4516 write_1d0(7, 0x19b, 3, 1);
4517 write_1d0(7, 0x1c0, 3, 1);
4518 write_1d0(4, 0x1c6, 4, 1);
4519 write_1d0(4, 0x1cc, 4, 1);
4520 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4521 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004522 MCHBAR32(0x584) = 0xfffff;
4523 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524
4525 for (channel = 0; channel < NUM_CHANNELS; channel++)
4526 for (slot = 0; slot < NUM_SLOTS; slot++)
4527 for (rank = 0; rank < NUM_RANKS; rank++)
4528 if (info.
4529 populated_ranks[channel][slot]
4530 [rank])
4531 config_rank(&info, s3resume,
4532 channel, slot,
4533 rank);
4534
Felix Held04be2dd2018-07-29 04:53:22 +02004535 MCHBAR8(0x243) = 0x1;
4536 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004537 }
4538
4539 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004540 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 write_26c(0, 0x820);
4542 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004543 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004544 /* end */
4545
4546 if (s3resume) {
4547 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004548 MCHBAR32(0x294 + (channel << 10)) =
4549 (info.populated_ranks_mask[channel] & 3) << 16;
4550 MCHBAR16(0x298 + (channel << 10)) =
4551 info.populated_ranks[channel][0][0] |
4552 (info.populated_ranks[channel][0][1] << 5);
4553 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004555 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556 }
4557
Felix Held04be2dd2018-07-29 04:53:22 +02004558 MCHBAR32_AND(0xfa4, ~0x01000002);
4559 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561 /* Before training. */
4562 timestamp_add_now(103);
4563
4564 if (!s3resume)
4565 ram_training(&info);
4566
4567 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004568 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569
4570 dump_timings(&info);
4571
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572 program_modules_memory_map(&info, 0);
4573 program_total_memory_map(&info);
4574
4575 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004576 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581 else
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR32_AND(0xfac, ~0x80000000);
4585 MCHBAR32(0xfb4) = 0x4800;
4586 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4587 MCHBAR32(0xe94) = 0x7ffff;
4588 MCHBAR32(0xfc0) = 0x80002040;
4589 MCHBAR32(0xfc4) = 0x701246;
4590 MCHBAR8_AND(0xfc8, ~0x70);
4591 MCHBAR32_OR(0xe5c, 0x1000000);
4592 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4593 MCHBAR32(0x50) = 0x700b0;
4594 MCHBAR32(0x3c) = 0x10;
4595 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4596 MCHBAR8_OR(0xff4, 0x2);
4597 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598
Felix Held29a9c072018-07-29 01:34:45 +02004599#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4601 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4602 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004603
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004604 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4605 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4606 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004607
4608#else
4609 {
4610 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004611 // = 0xe911714b
4612 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4613 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4614 // = 0xe911714b
4615 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4616 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004617 }
4618#endif
4619
4620 {
4621 u32 eax;
4622
4623 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004624 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4625 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4626 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627 }
4628
4629 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633 else
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637
Felix Held04be2dd2018-07-29 04:53:22 +02004638 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641 else
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 }
4644
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
4647 {
4648 u8 al;
4649 al = 0xd;
4650 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4651 al += 2;
4652 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004653 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654 }
4655
4656 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4658 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4659 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4660 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661 }
4662 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004663 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004664 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004665 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004666 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004667 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004668 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR8_OR(0x1210, 2);
4670 MCHBAR32(0x1200) = 0x8800440;
4671 MCHBAR32(0x1204) = 0x53ff0453;
4672 MCHBAR32(0x1208) = 0x19002043;
4673 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004674
4675 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004676 MCHBAR16(0x1214) = 0x220;
4677 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678 }
4679
Felix Held04be2dd2018-07-29 04:53:22 +02004680 MCHBAR8_OR(0x1214, 0x4);
4681 MCHBAR8(0x120c) = 0x1;
4682 MCHBAR8(0x1218) = 0x3;
4683 MCHBAR8(0x121a) = 0x3;
4684 MCHBAR8(0x121c) = 0x3;
4685 MCHBAR16(0xc14) = 0x0;
4686 MCHBAR16(0xc20) = 0x0;
4687 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688
4689 /* revision dependent here. */
4690
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692
4693 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004694 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR16_OR(0x1230, 0x8000);
4697 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698
4699 u8 bl, ebpb;
4700 u16 reg_1020;
4701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4703 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
Felix Held04be2dd2018-07-29 04:53:22 +02004705 MCHBAR32(0x1000) = 0x100;
4706 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707
4708 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004709 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710 bl = reg_1020 >> 8;
4711 ebpb = reg_1020 & 0xff;
4712 } else {
4713 ebpb = 0;
4714 bl = 8;
4715 }
4716
4717 rdmsr(0x1a2);
4718
Felix Held04be2dd2018-07-29 04:53:22 +02004719 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720
Felix Held04be2dd2018-07-29 04:53:22 +02004721 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722
Felix Held04be2dd2018-07-29 04:53:22 +02004723 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004727 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4728 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004729 }
4730
4731 setup_heci_uma(&info);
4732
4733 if (info.uma_enabled) {
4734 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004735 MCHBAR32_OR(0x11b0, 0x4000);
4736 MCHBAR32_OR(0x11b4, 0x4000);
4737 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004738
Felix Held04be2dd2018-07-29 04:53:22 +02004739 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4740 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4741 MCHBAR16_OR(0x1170, 0x1000);
4742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004744
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004745 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004746 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004747 ;
4748 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004749 }
4750
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004751 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4752 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004753 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004754 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004756 udelay(1000);
4757 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004758 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760 if (!s3resume)
4761 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004762 if (s3resume && cbmem_wasnot_inited) {
4763 u32 reg32;
4764 printk(BIOS_ERR, "Failed S3 resume.\n");
4765 ram_check(0x100000, 0x200000);
4766
4767 /* Clear SLP_TYPE. */
4768 reg32 = inl(DEFAULT_PMBASE + 0x04);
4769 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4770
4771 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004772 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004773 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004774}