blob: 33b225659e8d0e693bfc15be31f0d72a7b703545 [file] [log] [blame]
Patrick Georgi02363b52020-05-05 20:48:50 +02001/* This file is part of the coreboot project. */
Patrick Georgiac959032020-05-05 22:49:26 +02002/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01005#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01007#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02009#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Arthur Heymansdc71e252018-01-29 10:14:48 +010064#define MRC_CACHE_VERSION 1
65
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100104/* OK */
105static void write_1d0(u32 val, u16 addr, int bits, int flag)
106{
Felix Held04be2dd2018-07-29 04:53:22 +0200107 MCHBAR32(0x1d0) = 0;
108 while (MCHBAR32(0x1d0) & 0x800000)
109 ;
110 MCHBAR32(0x1d4) =
111 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
112 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200113 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200114 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100115}
116
117/* OK */
118static u16 read_1d0(u16 addr, int split)
119{
120 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200121 MCHBAR32(0x1d0) = 0;
122 while (MCHBAR32(0x1d0) & 0x800000)
123 ;
124 MCHBAR32(0x1d0) =
125 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
126 while (MCHBAR32(0x1d0) & 0x800000)
127 ;
128 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100129 write_1d0(0, 0x33d, 0, 0);
130 write_1d0(0, 0x33d, 0, 0);
131 val &= ((1 << split) - 1);
132 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
133 return val;
134}
135
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800136static void write32p(uintptr_t addr, uint32_t val)
137{
138 write32((void *)addr, val);
139}
140
141static uint32_t read32p(uintptr_t addr)
142{
143 return read32((void *)addr);
144}
145
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146static void sfence(void)
147{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100148 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100149}
150
151static inline u16 get_lane_offset(int slot, int rank, int lane)
152{
153 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
154 0x452 * (lane == 8);
155}
156
157static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
158{
159 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
160 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static u32 gav_real(int line, u32 in)
164{
165 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
166 return in;
167}
168
169#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200170
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100171struct raminfo {
172 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
173 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
174 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
175 u8 density[2][2]; /* [CHANNEL][SLOT] */
176 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
177 int rank_start[2][2][2];
178 u8 cas_latency;
179 u8 board_lane_delay[9];
180 u8 use_ecc;
181 u8 revision;
182 u8 max_supported_clock_speed_index;
183 u8 uma_enabled;
184 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
185 u8 silicon_revision;
186 u8 populated_ranks_mask[2];
187 u8 max_slots_used_in_channel;
188 u8 mode4030[2];
189 u16 avg4044[2];
190 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600191 unsigned int total_memory_mb;
192 unsigned int interleaved_part_mb;
193 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100194
195 u32 heci_bar;
196 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600197 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100198
199 struct ram_training training;
200 u32 last_500_command[2];
201
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100202 u32 delay46_ps[2];
203 u32 delay54_ps[2];
204 u8 revision_flag_1;
205 u8 some_delay_1_cycle_floor;
206 u8 some_delay_2_halfcycles_ceil;
207 u8 some_delay_3_ps_rounded;
208
209 const struct ram_training *cached_training;
210};
211
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200212/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100213timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200214
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100215static void
216write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
217 int flag);
218
219/* OK */
220static u16
221read_500(struct raminfo *info, int channel, u16 addr, int split)
222{
223 u32 val;
224 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200225 MCHBAR32(0x500 + (channel << 10)) = 0;
226 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
227 ;
228 MCHBAR32(0x500 + (channel << 10)) =
229 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
230 + 0xb88 - addr);
231 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
232 ;
233 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100234 return val & ((1 << split) - 1);
235}
236
237/* OK */
238static void
239write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
240 int flag)
241{
242 if (info->last_500_command[channel] == 0x80000000) {
243 info->last_500_command[channel] = 0x40000000;
244 write_500(info, channel, 0, 0xb61, 0, 0);
245 }
Felix Held04be2dd2018-07-29 04:53:22 +0200246 MCHBAR32(0x500 + (channel << 10)) = 0;
247 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
248 ;
249 MCHBAR32(0x504 + (channel << 10)) =
250 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
251 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200252 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200253 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100254}
255
256static int rw_test(int rank)
257{
258 const u32 mask = 0xf00fc33c;
259 int ok = 0xff;
260 int i;
261 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800262 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100263 sfence();
264 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800265 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100266 sfence();
267 for (i = 0; i < 32; i++) {
268 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800269 write32p((rank << 28) | (i << 3), pat);
270 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100271 }
272 sfence();
273 for (i = 0; i < 32; i++) {
274 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
275 int j;
276 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800277 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 for (j = 0; j < 4; j++)
279 if (((val >> (j * 8)) & 0xff) != pat)
280 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800281 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 for (j = 0; j < 4; j++)
283 if (((val >> (j * 8)) & 0xff) != pat)
284 ok &= ~(16 << j);
285 }
286 sfence();
287 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 sfence();
290 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800291 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100292
293 return ok;
294}
295
296static void
297program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
298{
299 int lane;
300 for (lane = 0; lane < 8; lane++) {
301 write_500(info, channel,
302 base +
303 info->training.
304 lane_timings[2][channel][slot][rank][lane],
305 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
306 write_500(info, channel,
307 base +
308 info->training.
309 lane_timings[3][channel][slot][rank][lane],
310 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
311 }
312}
313
314static void write_26c(int channel, u16 si)
315{
Felix Held04be2dd2018-07-29 04:53:22 +0200316 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
317 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
318 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100319}
320
321static u32 get_580(int channel, u8 addr)
322{
323 u32 ret;
324 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200325 MCHBAR8(0x5ff) = 0x0;
326 MCHBAR8(0x5ff) = 0x80;
327 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
328 MCHBAR8_OR(0x580 + (channel << 10), 1);
329 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
330 ;
331 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332 return ret;
333}
334
335const int cached_config = 0;
336
337#define NUM_CHANNELS 2
338#define NUM_SLOTS 2
339#define NUM_RANKS 2
340#define RANK_SHIFT 28
341#define CHANNEL_SHIFT 10
342
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100343static void seq9(struct raminfo *info, int channel, int slot, int rank)
344{
345 int i, lane;
346
347 for (i = 0; i < 2; i++)
348 for (lane = 0; lane < 8; lane++)
349 write_500(info, channel,
350 info->training.lane_timings[i +
351 1][channel][slot]
352 [rank][lane], get_timing_register_addr(lane,
353 i + 1,
354 slot,
355 rank),
356 9, 0);
357
358 write_1d0(1, 0x103, 6, 1);
359 for (lane = 0; lane < 8; lane++)
360 write_500(info, channel,
361 info->training.
362 lane_timings[0][channel][slot][rank][lane],
363 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
364
365 for (i = 0; i < 2; i++) {
366 for (lane = 0; lane < 8; lane++)
367 write_500(info, channel,
368 info->training.lane_timings[i +
369 1][channel][slot]
370 [rank][lane], get_timing_register_addr(lane,
371 i + 1,
372 slot,
373 rank),
374 9, 0);
375 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
376 }
377
378 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200379 MCHBAR8(0x5ff) = 0x0;
380 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100381 write_1d0(0x2, 0x142, 3, 1);
382 for (lane = 0; lane < 8; lane++) {
383 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
384 info->training.lane_timings[2][channel][slot][rank][lane] =
385 read_500(info, channel,
386 get_timing_register_addr(lane, 2, slot, rank), 9);
387 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
388 info->training.lane_timings[3][channel][slot][rank][lane] =
389 info->training.lane_timings[2][channel][slot][rank][lane] +
390 0x20;
391 }
392}
393
394static int count_ranks_in_channel(struct raminfo *info, int channel)
395{
396 int slot, rank;
397 int res = 0;
398 for (slot = 0; slot < NUM_SLOTS; slot++)
399 for (rank = 0; rank < NUM_SLOTS; rank++)
400 res += info->populated_ranks[channel][slot][rank];
401 return res;
402}
403
404static void
405config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
406{
407 int add;
408
409 write_1d0(0, 0x178, 7, 1);
410 seq9(info, channel, slot, rank);
411 program_timings(info, 0x80, channel, slot, rank);
412
413 if (channel == 0)
414 add = count_ranks_in_channel(info, 1);
415 else
416 add = 0;
417 if (!s3resume)
418 gav(rw_test(rank + add));
419 program_timings(info, 0x00, channel, slot, rank);
420 if (!s3resume)
421 gav(rw_test(rank + add));
422 if (!s3resume)
423 gav(rw_test(rank + add));
424 write_1d0(0, 0x142, 3, 1);
425 write_1d0(0, 0x103, 6, 1);
426
427 gav(get_580(channel, 0xc | (rank << 5)));
428 gav(read_1d0(0x142, 3));
429
Felix Held04be2dd2018-07-29 04:53:22 +0200430 MCHBAR8(0x5ff) = 0x0;
431 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100432}
433
434static void set_4cf(struct raminfo *info, int channel, u8 val)
435{
436 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
437 write_500(info, channel, val, 0x4cf, 4, 1);
438 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
439 write_500(info, channel, val, 0x659, 4, 1);
440 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
441 write_500(info, channel, val, 0x697, 4, 1);
442}
443
444static void set_334(int zero)
445{
446 int j, k, channel;
447 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
448 u32 vd8[2][16];
449
450 for (channel = 0; channel < NUM_CHANNELS; channel++) {
451 for (j = 0; j < 4; j++) {
452 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
453 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
454 u16 c;
455 if ((j == 0 || j == 3) && zero)
456 c = 0;
457 else if (j == 3)
458 c = 0x5f;
459 else
460 c = 0x5f5f;
461
462 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200463 MCHBAR32(0x138 + 8 * k) =
464 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100465 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200466 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100467 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200468 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100469 }
470
Felix Held22ca8cb2018-07-29 05:09:44 +0200471 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
472 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200473 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
474 zero ? 0 : (0x18191819 & lmask);
475 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
476 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : (a & lmask);
478 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
479 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100480 }
481 }
482
Felix Held04be2dd2018-07-29 04:53:22 +0200483 MCHBAR32_OR(0x130, 1);
484 while (MCHBAR8(0x130) & 1)
485 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486}
487
488static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
489{
490 u32 v;
491 v = read_1d0(addr, split);
492 write_1d0((v & and) | or, addr, split, flag);
493}
494
495static int find_highest_bit_set(u16 val)
496{
497 int i;
498 for (i = 15; i >= 0; i--)
499 if (val & (1 << i))
500 return i;
501 return -1;
502}
503
504static int find_lowest_bit_set32(u32 val)
505{
506 int i;
507 for (i = 0; i < 32; i++)
508 if (val & (1 << i))
509 return i;
510 return -1;
511}
512
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100513enum {
514 DEVICE_TYPE = 2,
515 MODULE_TYPE = 3,
516 DENSITY = 4,
517 RANKS_AND_DQ = 7,
518 MEMORY_BUS_WIDTH = 8,
519 TIMEBASE_DIVIDEND = 10,
520 TIMEBASE_DIVISOR = 11,
521 CYCLETIME = 12,
522
523 CAS_LATENCIES_LSB = 14,
524 CAS_LATENCIES_MSB = 15,
525 CAS_LATENCY_TIME = 16,
526 THERMAL_AND_REFRESH = 31,
527 REFERENCE_RAW_CARD_USED = 62,
528 RANK1_ADDRESS_MAPPING = 63
529};
530
531static void calculate_timings(struct raminfo *info)
532{
Martin Roth468d02c2019-10-23 21:44:42 -0600533 unsigned int cycletime;
534 unsigned int cas_latency_time;
535 unsigned int supported_cas_latencies;
536 unsigned int channel, slot;
537 unsigned int clock_speed_index;
538 unsigned int min_cas_latency;
539 unsigned int cas_latency;
540 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100541
542 /* Find common CAS latency */
543 supported_cas_latencies = 0x3fe;
544 for (channel = 0; channel < NUM_CHANNELS; channel++)
545 for (slot = 0; slot < NUM_SLOTS; slot++)
546 if (info->populated_ranks[channel][slot][0])
547 supported_cas_latencies &=
548 2 *
549 (info->
550 spd[channel][slot][CAS_LATENCIES_LSB] |
551 (info->
552 spd[channel][slot][CAS_LATENCIES_MSB] <<
553 8));
554
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100555 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100556
557 cycletime = min_cycletime[max_clock_index];
558 cas_latency_time = min_cas_latency_time[max_clock_index];
559
560 for (channel = 0; channel < NUM_CHANNELS; channel++)
561 for (slot = 0; slot < NUM_SLOTS; slot++)
562 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600563 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100564 timebase =
565 1000 *
566 info->
567 spd[channel][slot][TIMEBASE_DIVIDEND] /
568 info->spd[channel][slot][TIMEBASE_DIVISOR];
569 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100570 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100571 timebase *
572 info->spd[channel][slot][CYCLETIME]);
573 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100574 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100575 timebase *
576 info->
577 spd[channel][slot][CAS_LATENCY_TIME]);
578 }
Jacob Garber3c193822019-06-10 18:23:32 -0600579 if (cycletime > min_cycletime[0])
580 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100581 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
582 if (cycletime == min_cycletime[clock_speed_index])
583 break;
584 if (cycletime > min_cycletime[clock_speed_index]) {
585 clock_speed_index--;
586 cycletime = min_cycletime[clock_speed_index];
587 break;
588 }
589 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100590 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100591 cas_latency = 0;
592 while (supported_cas_latencies) {
593 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
594 if (cas_latency <= min_cas_latency)
595 break;
596 supported_cas_latencies &=
597 ~(1 << find_highest_bit_set(supported_cas_latencies));
598 }
599
600 if (cas_latency != min_cas_latency && clock_speed_index)
601 clock_speed_index--;
602
603 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
604 die("Couldn't configure DRAM");
605 info->clock_speed_index = clock_speed_index;
606 info->cas_latency = cas_latency;
607}
608
609static void program_base_timings(struct raminfo *info)
610{
Martin Roth468d02c2019-10-23 21:44:42 -0600611 unsigned int channel;
612 unsigned int slot, rank, lane;
613 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100614 int i;
615
616 extended_silicon_revision = info->silicon_revision;
617 if (info->silicon_revision == 0)
618 for (channel = 0; channel < NUM_CHANNELS; channel++)
619 for (slot = 0; slot < NUM_SLOTS; slot++)
620 if ((info->
621 spd[channel][slot][MODULE_TYPE] & 0xF) ==
622 3)
623 extended_silicon_revision = 4;
624
625 for (channel = 0; channel < NUM_CHANNELS; channel++) {
626 for (slot = 0; slot < NUM_SLOTS; slot++)
627 for (rank = 0; rank < NUM_SLOTS; rank++) {
628 int card_timing_2;
629 if (!info->populated_ranks[channel][slot][rank])
630 continue;
631
632 for (lane = 0; lane < 9; lane++) {
633 int tm_reg;
634 int card_timing;
635
636 card_timing = 0;
637 if ((info->
638 spd[channel][slot][MODULE_TYPE] &
639 0xF) == 3) {
640 int reference_card;
641 reference_card =
642 info->
643 spd[channel][slot]
644 [REFERENCE_RAW_CARD_USED] &
645 0x1f;
646 if (reference_card == 3)
647 card_timing =
648 u16_ffd1188[0][lane]
649 [info->
650 clock_speed_index];
651 if (reference_card == 5)
652 card_timing =
653 u16_ffd1188[1][lane]
654 [info->
655 clock_speed_index];
656 }
657
658 info->training.
659 lane_timings[0][channel][slot][rank]
660 [lane] =
661 u8_FFFD1218[info->
662 clock_speed_index];
663 info->training.
664 lane_timings[1][channel][slot][rank]
665 [lane] = 256;
666
667 for (tm_reg = 2; tm_reg < 4; tm_reg++)
668 info->training.
669 lane_timings[tm_reg]
670 [channel][slot][rank][lane]
671 =
672 u8_FFFD1240[channel]
673 [extended_silicon_revision]
674 [lane][2 * slot +
675 rank][info->
676 clock_speed_index]
677 + info->max4048[channel]
678 +
679 u8_FFFD0C78[channel]
680 [extended_silicon_revision]
681 [info->
682 mode4030[channel]][slot]
683 [rank][info->
684 clock_speed_index]
685 + card_timing;
686 for (tm_reg = 0; tm_reg < 4; tm_reg++)
687 write_500(info, channel,
688 info->training.
689 lane_timings[tm_reg]
690 [channel][slot][rank]
691 [lane],
692 get_timing_register_addr
693 (lane, tm_reg, slot,
694 rank), 9, 0);
695 }
696
697 card_timing_2 = 0;
698 if (!(extended_silicon_revision != 4
699 || (info->
700 populated_ranks_mask[channel] & 5) ==
701 5)) {
702 if ((info->
703 spd[channel][slot]
704 [REFERENCE_RAW_CARD_USED] & 0x1F)
705 == 3)
706 card_timing_2 =
707 u16_FFFE0EB8[0][info->
708 clock_speed_index];
709 if ((info->
710 spd[channel][slot]
711 [REFERENCE_RAW_CARD_USED] & 0x1F)
712 == 5)
713 card_timing_2 =
714 u16_FFFE0EB8[1][info->
715 clock_speed_index];
716 }
717
718 for (i = 0; i < 3; i++)
719 write_500(info, channel,
720 (card_timing_2 +
721 info->max4048[channel]
722 +
723 u8_FFFD0EF8[channel]
724 [extended_silicon_revision]
725 [info->
726 mode4030[channel]][info->
727 clock_speed_index]),
728 u16_fffd0c50[i][slot][rank],
729 8, 1);
730 write_500(info, channel,
731 (info->max4048[channel] +
732 u8_FFFD0C78[channel]
733 [extended_silicon_revision][info->
734 mode4030
735 [channel]]
736 [slot][rank][info->
737 clock_speed_index]),
738 u16_fffd0c70[slot][rank], 7, 1);
739 }
740 if (!info->populated_ranks_mask[channel])
741 continue;
742 for (i = 0; i < 3; i++)
743 write_500(info, channel,
744 (info->max4048[channel] +
745 info->avg4044[channel]
746 +
747 u8_FFFD17E0[channel]
748 [extended_silicon_revision][info->
749 mode4030
750 [channel]][info->
751 clock_speed_index]),
752 u16_fffd0c68[i], 8, 1);
753 }
754}
755
756static unsigned int fsbcycle_ps(struct raminfo *info)
757{
758 return 900000 / info->fsb_frequency;
759}
760
761/* The time of DDR transfer in ps. */
762static unsigned int halfcycle_ps(struct raminfo *info)
763{
764 return 3750 / (info->clock_speed_index + 3);
765}
766
767/* The time of clock cycle in ps. */
768static unsigned int cycle_ps(struct raminfo *info)
769{
770 return 2 * halfcycle_ps(info);
771}
772
773/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600774static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100775{
776 return (info->clock_speed_index + 3) * 120;
777}
778
779/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600780static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100781{
782 return 100 * frequency_11(info) / 9;
783}
784
Martin Roth468d02c2019-10-23 21:44:42 -0600785static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786{
787 return (frequency_11(info) * 2) * ps / 900000;
788}
789
Martin Roth468d02c2019-10-23 21:44:42 -0600790static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100791{
792 return (frequency_11(info)) * ns / 900;
793}
794
795static void compute_derived_timings(struct raminfo *info)
796{
Martin Roth468d02c2019-10-23 21:44:42 -0600797 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100798 int extended_silicon_revision;
799 int some_delay_1_ps;
800 int some_delay_2_ps;
801 int some_delay_2_halfcycles_ceil;
802 int some_delay_2_halfcycles_floor;
803 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100804 int some_delay_3_ps_rounded;
805 int some_delay_1_cycle_ceil;
806 int some_delay_1_cycle_floor;
807
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100808 some_delay_3_ps_rounded = 0;
809 extended_silicon_revision = info->silicon_revision;
810 if (!info->silicon_revision)
811 for (channel = 0; channel < NUM_CHANNELS; channel++)
812 for (slot = 0; slot < NUM_SLOTS; slot++)
813 if ((info->
814 spd[channel][slot][MODULE_TYPE] & 0xF) ==
815 3)
816 extended_silicon_revision = 4;
817 if (info->board_lane_delay[7] < 5)
818 info->board_lane_delay[7] = 5;
819 info->revision_flag_1 = 2;
820 if (info->silicon_revision == 2 || info->silicon_revision == 3)
821 info->revision_flag_1 = 0;
822 if (info->revision < 16)
823 info->revision_flag_1 = 0;
824
825 if (info->revision < 8)
826 info->revision_flag_1 = 0;
827 if (info->revision >= 8 && (info->silicon_revision == 0
828 || info->silicon_revision == 1))
829 some_delay_2_ps = 735;
830 else
831 some_delay_2_ps = 750;
832
833 if (info->revision >= 0x10 && (info->silicon_revision == 0
834 || info->silicon_revision == 1))
835 some_delay_1_ps = 3929;
836 else
837 some_delay_1_ps = 3490;
838
839 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
840 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
841 if (some_delay_1_ps % cycle_ps(info))
842 some_delay_1_cycle_ceil++;
843 else
844 some_delay_1_cycle_floor--;
845 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
846 if (info->revision_flag_1)
847 some_delay_2_ps = halfcycle_ps(info) >> 6;
848 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100849 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100850 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
851 375;
852 some_delay_3_ps =
853 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
854 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200855 if (some_delay_3_ps >= 150) {
856 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100857 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200858 some_delay_3_ps_rounded =
859 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
860 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100861 }
862 some_delay_2_halfcycles_ceil =
863 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
864 2 * (some_delay_1_cycle_ceil - 1);
865 if (info->revision_flag_1 && some_delay_3_ps < 150)
866 some_delay_2_halfcycles_ceil++;
867 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
868 if (info->revision < 0x10)
869 some_delay_2_halfcycles_floor =
870 some_delay_2_halfcycles_ceil - 1;
871 if (!info->revision_flag_1)
872 some_delay_2_halfcycles_floor++;
873 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
874 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
875 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
876 || (info->populated_ranks[1][0][0]
877 && info->populated_ranks[1][1][0]))
878 info->max_slots_used_in_channel = 2;
879 else
880 info->max_slots_used_in_channel = 1;
881 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200882 MCHBAR32(0x244 + (channel << 10)) =
883 ((info->revision < 8) ? 1 : 0x200) |
884 ((2 - info->max_slots_used_in_channel) << 17) |
885 (channel << 21) |
886 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100887 if (info->max_slots_used_in_channel == 1) {
888 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
889 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
890 } else {
891 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 */
892 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
893 || (count_ranks_in_channel(info, 1) ==
894 2)) ? 2 : 3;
895 }
896 for (channel = 0; channel < NUM_CHANNELS; channel++) {
897 int max_of_unk;
898 int min_of_unk_2;
899
900 int i, count;
901 int sum;
902
903 if (!info->populated_ranks_mask[channel])
904 continue;
905
906 max_of_unk = 0;
907 min_of_unk_2 = 32767;
908
909 sum = 0;
910 count = 0;
911 for (i = 0; i < 3; i++) {
912 int unk1;
913 if (info->revision < 8)
914 unk1 =
915 u8_FFFD1891[0][channel][info->
916 clock_speed_index]
917 [i];
918 else if (!
919 (info->revision >= 0x10
920 || info->revision_flag_1))
921 unk1 =
922 u8_FFFD1891[1][channel][info->
923 clock_speed_index]
924 [i];
925 else
926 unk1 = 0;
927 for (slot = 0; slot < NUM_SLOTS; slot++)
928 for (rank = 0; rank < NUM_RANKS; rank++) {
929 int a = 0;
930 int b = 0;
931
932 if (!info->
933 populated_ranks[channel][slot]
934 [rank])
935 continue;
936 if (extended_silicon_revision == 4
937 && (info->
938 populated_ranks_mask[channel] &
939 5) != 5) {
940 if ((info->
941 spd[channel][slot]
942 [REFERENCE_RAW_CARD_USED] &
943 0x1F) == 3) {
944 a = u16_ffd1178[0]
945 [info->
946 clock_speed_index];
947 b = u16_fe0eb8[0][info->
948 clock_speed_index];
949 } else
950 if ((info->
951 spd[channel][slot]
952 [REFERENCE_RAW_CARD_USED]
953 & 0x1F) == 5) {
954 a = u16_ffd1178[1]
955 [info->
956 clock_speed_index];
957 b = u16_fe0eb8[1][info->
958 clock_speed_index];
959 }
960 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100961 min_of_unk_2 = MIN(min_of_unk_2, a);
962 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100963 if (rank == 0) {
964 sum += a;
965 count++;
966 }
967 {
968 int t;
969 t = b +
970 u8_FFFD0EF8[channel]
971 [extended_silicon_revision]
972 [info->
973 mode4030[channel]][info->
974 clock_speed_index];
975 if (unk1 >= t)
976 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100977 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100978 unk1 - t);
979 }
980 }
981 {
982 int t =
983 u8_FFFD17E0[channel]
984 [extended_silicon_revision][info->
985 mode4030
986 [channel]]
987 [info->clock_speed_index] + min_of_unk_2;
988 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100989 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100990 }
991 }
992
Jacob Garber64fb4a32019-06-10 17:29:18 -0600993 if (count == 0)
994 die("No memory ranks found for channel %u\n", channel);
995
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100996 info->avg4044[channel] = sum / count;
997 info->max4048[channel] = max_of_unk;
998 }
999}
1000
1001static void jedec_read(struct raminfo *info,
1002 int channel, int slot, int rank,
1003 int total_rank, u8 addr3, unsigned int value)
1004{
1005 /* Handle mirrored mapping. */
1006 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001007 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1008 ((addr3 >> 1) & 0x10);
1009 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1010 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001011
1012 /* Handle mirrored mapping. */
1013 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1014 value =
1015 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1016 << 1);
1017
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001018 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001019
Felix Held04be2dd2018-07-29 04:53:22 +02001020 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1021 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001023 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001024}
1025
1026enum {
1027 MR1_RZQ12 = 512,
1028 MR1_RZQ2 = 64,
1029 MR1_RZQ4 = 4,
1030 MR1_ODS34OHM = 2
1031};
1032
1033enum {
1034 MR0_BT_INTERLEAVED = 8,
1035 MR0_DLL_RESET_ON = 256
1036};
1037
1038enum {
1039 MR2_RTT_WR_DISABLED = 0,
1040 MR2_RZQ2 = 1 << 10
1041};
1042
1043static void jedec_init(struct raminfo *info)
1044{
1045 int write_recovery;
1046 int channel, slot, rank;
1047 int total_rank;
1048 int dll_on;
1049 int self_refresh_temperature;
1050 int auto_self_refresh;
1051
1052 auto_self_refresh = 1;
1053 self_refresh_temperature = 1;
1054 if (info->board_lane_delay[3] <= 10) {
1055 if (info->board_lane_delay[3] <= 8)
1056 write_recovery = info->board_lane_delay[3] - 4;
1057 else
1058 write_recovery = 5;
1059 } else {
1060 write_recovery = 6;
1061 }
1062 FOR_POPULATED_RANKS {
1063 auto_self_refresh &=
1064 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1065 self_refresh_temperature &=
1066 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1067 }
1068 if (auto_self_refresh == 1)
1069 self_refresh_temperature = 0;
1070
1071 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1072 || (info->populated_ranks[0][0][0]
1073 && info->populated_ranks[0][1][0])
1074 || (info->populated_ranks[1][0][0]
1075 && info->populated_ranks[1][1][0]));
1076
1077 total_rank = 0;
1078
1079 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1080 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1081 int rzq_reg58e;
1082
1083 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1084 rzq_reg58e = 64;
1085 rtt = MR1_RZQ2;
1086 if (info->clock_speed_index != 0) {
1087 rzq_reg58e = 4;
1088 if (info->populated_ranks_mask[channel] == 3)
1089 rtt = MR1_RZQ4;
1090 }
1091 } else {
1092 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1093 rtt = MR1_RZQ12;
1094 rzq_reg58e = 64;
1095 rtt_wr = MR2_RZQ2;
1096 } else {
1097 rzq_reg58e = 4;
1098 rtt = MR1_RZQ4;
1099 }
1100 }
1101
Felix Held04be2dd2018-07-29 04:53:22 +02001102 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1103 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1104 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1105 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1106 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001107
1108 for (slot = 0; slot < NUM_SLOTS; slot++)
1109 for (rank = 0; rank < NUM_RANKS; rank++)
1110 if (info->populated_ranks[channel][slot][rank]) {
1111 jedec_read(info, channel, slot, rank,
1112 total_rank, 0x28,
1113 rtt_wr | (info->
1114 clock_speed_index
1115 << 3)
1116 | (auto_self_refresh << 6) |
1117 (self_refresh_temperature <<
1118 7));
1119 jedec_read(info, channel, slot, rank,
1120 total_rank, 0x38, 0);
1121 jedec_read(info, channel, slot, rank,
1122 total_rank, 0x18,
1123 rtt | MR1_ODS34OHM);
1124 jedec_read(info, channel, slot, rank,
1125 total_rank, 6,
1126 (dll_on << 12) |
1127 (write_recovery << 9)
1128 | ((info->cas_latency - 4) <<
1129 4) | MR0_BT_INTERLEAVED |
1130 MR0_DLL_RESET_ON);
1131 total_rank++;
1132 }
1133 }
1134}
1135
1136static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1137{
Martin Roth468d02c2019-10-23 21:44:42 -06001138 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001139 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1140 unsigned int channel_0_non_interleaved;
1141
1142 FOR_ALL_RANKS {
1143 if (info->populated_ranks[channel][slot][rank]) {
1144 total_mb[channel] +=
1145 pre_jedec ? 256 : (256 << info->
1146 density[channel][slot] >> info->
1147 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001148 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1149 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1150 (info->is_x16_module[channel][slot] |
1151 ((info->density[channel][slot] + 1) << 1))) |
1152 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001153 }
Felix Held04be2dd2018-07-29 04:53:22 +02001154 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1155 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001156 }
1157
1158 info->total_memory_mb = total_mb[0] + total_mb[1];
1159
1160 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001161 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001162 info->non_interleaved_part_mb =
1163 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1164 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001165 MCHBAR32(0x100) = channel_0_non_interleaved |
1166 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001168 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001169}
1170
1171static void program_board_delay(struct raminfo *info)
1172{
1173 int cas_latency_shift;
1174 int some_delay_ns;
1175 int some_delay_3_half_cycles;
1176
Martin Roth468d02c2019-10-23 21:44:42 -06001177 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001178 int high_multiplier;
1179 int lane_3_delay;
1180 int cas_latency_derived;
1181
1182 high_multiplier = 0;
1183 some_delay_ns = 200;
1184 some_delay_3_half_cycles = 4;
1185 cas_latency_shift = info->silicon_revision == 0
1186 || info->silicon_revision == 1 ? 1 : 0;
1187 if (info->revision < 8) {
1188 some_delay_ns = 600;
1189 cas_latency_shift = 0;
1190 }
1191 {
1192 int speed_bit;
1193 speed_bit =
1194 ((info->clock_speed_index > 1
1195 || (info->silicon_revision != 2
1196 && info->silicon_revision != 3))) ^ (info->revision >=
1197 0x10);
1198 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1199 3, 1);
1200 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1201 3, 1);
1202 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1203 && (info->silicon_revision == 2
1204 || info->silicon_revision == 3))
1205 rmw_1d0(0x116, 5, 2, 4, 1);
1206 }
Felix Held04be2dd2018-07-29 04:53:22 +02001207 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1208 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001209
Felix Held04be2dd2018-07-29 04:53:22 +02001210 MCHBAR8(0x124) = info->board_lane_delay[4] +
1211 ((frequency_01(info) + 999) / 1000);
1212 MCHBAR16(0x125) = 0x1360;
1213 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001215 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001216 high_multiplier = 1;
1217 some_delay_2_half_cycles = ps_to_halfcycles(info,
1218 ((3 *
1219 fsbcycle_ps(info))
1220 >> 1) +
1221 (halfcycle_ps(info)
1222 *
1223 reg178_min[info->
1224 clock_speed_index]
1225 >> 6)
1226 +
1227 4 *
1228 halfcycle_ps(info)
1229 + 2230);
1230 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001231 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001232 (frequency_11(info) * 2) * (28 -
1233 some_delay_2_half_cycles) /
1234 (frequency_11(info) * 2 -
1235 4 * (info->fsb_frequency))) >> 3, 7);
1236 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001237 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001238 some_delay_3_half_cycles = 3;
1239 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001240 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1241 MCHBAR32(0x224 + (channel << 10)) =
1242 (info->max_slots_used_in_channel - 1) |
1243 ((info->cas_latency - 5 - info->clock_speed_index)
1244 << 21) | ((info->max_slots_used_in_channel +
1245 info->cas_latency - cas_latency_shift - 4) << 16) |
1246 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1247 ((info->cas_latency - info->clock_speed_index +
1248 info->max_slots_used_in_channel - 6) << 8);
1249 MCHBAR32(0x228 + (channel << 10)) =
1250 info->max_slots_used_in_channel;
1251 MCHBAR8(0x239 + (channel << 10)) = 32;
1252 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1253 (some_delay_3_half_cycles << 25) | 0x840000;
1254 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1255 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1256 MCHBAR32(0x24c + (channel << 10)) =
1257 ((!!info->clock_speed_index) << 17) |
1258 (((2 + info->clock_speed_index -
1259 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260
Felix Held04be2dd2018-07-29 04:53:22 +02001261 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1262 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1263 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001264
1265 write_500(info, channel,
1266 ((!info->populated_ranks[channel][1][1])
1267 | (!info->populated_ranks[channel][1][0] << 1)
1268 | (!info->populated_ranks[channel][0][1] << 2)
1269 | (!info->populated_ranks[channel][0][0] << 3)),
1270 0x4c9, 4, 1);
1271 }
1272
Felix Held22ca8cb2018-07-29 05:09:44 +02001273 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274 {
1275 u8 freq_divisor = 2;
1276 if (info->fsb_frequency == frequency_11(info))
1277 freq_divisor = 3;
1278 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1279 freq_divisor = 1;
1280 else
1281 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001282 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001283 }
1284
1285 if (info->board_lane_delay[3] <= 10) {
1286 if (info->board_lane_delay[3] <= 8)
1287 lane_3_delay = info->board_lane_delay[3];
1288 else
1289 lane_3_delay = 10;
1290 } else {
1291 lane_3_delay = 12;
1292 }
1293 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1294 if (info->clock_speed_index > 1)
1295 cas_latency_derived++;
1296 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001297 MCHBAR32(0x240 + (channel << 10)) =
1298 ((info->clock_speed_index == 0) * 0x11000) |
1299 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1300 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001301 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1302 0x609, 6, 1);
1303 write_500(info, channel,
1304 info->clock_speed_index + 2 * info->cas_latency - 7,
1305 0x601, 6, 1);
1306
Felix Held04be2dd2018-07-29 04:53:22 +02001307 MCHBAR32(0x250 + (channel << 10)) =
1308 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1309 (info->board_lane_delay[7] << 2) |
1310 (info->board_lane_delay[4] << 16) |
1311 (info->board_lane_delay[1] << 25) |
1312 (info->board_lane_delay[1] << 29) | 1;
1313 MCHBAR32(0x254 + (channel << 10)) =
1314 (info->board_lane_delay[1] >> 3) |
1315 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1316 0x80 | (info->board_lane_delay[6] << 1) |
1317 (info->board_lane_delay[2] << 28) |
1318 (cas_latency_derived << 16) | 0x4700000;
1319 MCHBAR32(0x258 + (channel << 10)) =
1320 ((info->board_lane_delay[5] + info->clock_speed_index +
1321 9) << 12) | ((info->clock_speed_index -
1322 info->cas_latency + 12) << 8) |
1323 (info->board_lane_delay[2] << 17) |
1324 (info->board_lane_delay[4] << 24) | 0x47;
1325 MCHBAR32(0x25c + (channel << 10)) =
1326 (info->board_lane_delay[1] << 1) |
1327 (info->board_lane_delay[0] << 8) | 0x1da50000;
1328 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1329 MCHBAR8(0x5f8 + (channel << 10)) =
1330 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001331 }
1332
1333 program_modules_memory_map(info, 1);
1334
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001335 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001336 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1337 MCHBAR16_OR(0x612, 0x100);
1338 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001340 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001342 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001343 }
1344}
1345
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001346#define DEFAULT_PCI_MMIO_SIZE 2048
1347#define HOST_BRIDGE PCI_DEVFN(0, 0)
1348
1349static unsigned int get_mmio_size(void)
1350{
1351 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001352 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001353
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001354 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001355 if (dev)
1356 cfg = dev->chip_info;
1357
1358 /* If this is zero, it just means devicetree.cb didn't set it */
1359 if (!cfg || cfg->pci_mmio_size == 0)
1360 return DEFAULT_PCI_MMIO_SIZE;
1361 else
1362 return cfg->pci_mmio_size;
1363}
1364
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001365#define BETTER_MEMORY_MAP 0
1366
1367static void program_total_memory_map(struct raminfo *info)
1368{
1369 unsigned int TOM, TOLUD, TOUUD;
1370 unsigned int quickpath_reserved;
1371 unsigned int REMAPbase;
1372 unsigned int uma_base_igd;
1373 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001374 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001375 int memory_remap;
1376 unsigned int memory_map[8];
1377 int i;
1378 unsigned int current_limit;
1379 unsigned int tseg_base;
1380 int uma_size_igd = 0, uma_size_gtt = 0;
1381
1382 memset(memory_map, 0, sizeof(memory_map));
1383
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001384 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001385 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001386 gav(t);
1387 const int uma_sizes_gtt[16] =
1388 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1389 /* Igd memory */
1390 const int uma_sizes_igd[16] = {
1391 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1392 256, 512
1393 };
1394
1395 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1396 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1397 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001398
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001399 mmio_size = get_mmio_size();
1400
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401 TOM = info->total_memory_mb;
1402 if (TOM == 4096)
1403 TOM = 4032;
1404 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001405 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001406 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001407 memory_remap = 0;
1408 if (TOUUD - TOLUD > 64) {
1409 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001410 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001411 TOUUD = TOUUD - TOLUD + 4096;
1412 }
1413 if (TOUUD > 4096)
1414 memory_map[2] = TOUUD | 1;
1415 quickpath_reserved = 0;
1416
Jacob Garber975a7e32019-06-10 16:32:47 -06001417 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418
Jacob Garber975a7e32019-06-10 16:32:47 -06001419 gav(t);
1420
1421 if (t & 0x800) {
1422 u32 shift = t >> 20;
1423 if (shift == 0)
1424 die("Quickpath value is 0\n");
1425 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001427
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001428 if (memory_remap)
1429 TOUUD -= quickpath_reserved;
1430
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001431 uma_base_igd = TOLUD - uma_size_igd;
1432 uma_base_gtt = uma_base_igd - uma_size_gtt;
1433 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1434 if (!memory_remap)
1435 tseg_base -= quickpath_reserved;
1436 tseg_base = ALIGN_DOWN(tseg_base, 8);
1437
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001438 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1439 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001441 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1442 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001444 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445
1446 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001447 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1448 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001450 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451
1452 current_limit = 0;
1453 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1454 memory_map[1] = 4096;
1455 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001456 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001457 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1459 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001460 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 }
1462}
1463
1464static void collect_system_info(struct raminfo *info)
1465{
1466 u32 capid0[3];
1467 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001468 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469
1470 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001471 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1472 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001473
1474 if (!info->heci_bar)
1475 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001476 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477 if (!info->memory_reserved_for_heci_mb) {
1478 /* Wait for ME to be ready */
1479 intel_early_me_init();
1480 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1481 }
1482
1483 for (i = 0; i < 3; i++)
1484 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001485 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1486 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1488
1489 if ((capid0[1] >> 11) & 1)
1490 info->uma_enabled = 0;
1491 else
1492 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001493 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1495 info->silicon_revision = 0;
1496
1497 if (capid0[2] & 2) {
1498 info->silicon_revision = 0;
1499 info->max_supported_clock_speed_index = 2;
1500 for (channel = 0; channel < NUM_CHANNELS; channel++)
1501 if (info->populated_ranks[channel][0][0]
1502 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1503 3) {
1504 info->silicon_revision = 2;
1505 info->max_supported_clock_speed_index = 1;
1506 }
1507 } else {
1508 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1509 case 1:
1510 case 2:
1511 info->silicon_revision = 3;
1512 break;
1513 case 3:
1514 info->silicon_revision = 0;
1515 break;
1516 case 0:
1517 info->silicon_revision = 2;
1518 break;
1519 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001520 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001521 case 0x40:
1522 info->silicon_revision = 0;
1523 break;
1524 case 0x48:
1525 info->silicon_revision = 1;
1526 break;
1527 }
1528 }
1529}
1530
1531static void write_training_data(struct raminfo *info)
1532{
1533 int tm, channel, slot, rank, lane;
1534 if (info->revision < 8)
1535 return;
1536
1537 for (tm = 0; tm < 4; tm++)
1538 for (channel = 0; channel < NUM_CHANNELS; channel++)
1539 for (slot = 0; slot < NUM_SLOTS; slot++)
1540 for (rank = 0; rank < NUM_RANKS; rank++)
1541 for (lane = 0; lane < 9; lane++)
1542 write_500(info, channel,
1543 info->
1544 cached_training->
1545 lane_timings[tm]
1546 [channel][slot][rank]
1547 [lane],
1548 get_timing_register_addr
1549 (lane, tm, slot,
1550 rank), 9, 0);
1551 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1552 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1553}
1554
1555static void dump_timings(struct raminfo *info)
1556{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001558 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001560 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001561 slot, rank);
1562 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001563 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001564 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001565 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001566 read_500(info, channel,
1567 get_timing_register_addr
1568 (lane, i, slot, rank),
1569 9),
1570 info->training.
1571 lane_timings[i][channel][slot][rank]
1572 [lane]);
1573 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001574 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575 }
1576 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001577 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001579 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581}
1582
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001583/* Read timings and other registers that need to be restored verbatim and
1584 put them to CBMEM.
1585 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586static void save_timings(struct raminfo *info)
1587{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589 int channel, slot, rank, lane, i;
1590
1591 train = info->training;
1592 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1593 for (i = 0; i < 4; i++)
1594 train.lane_timings[i][channel][slot][rank][lane] =
1595 read_500(info, channel,
1596 get_timing_register_addr(lane, i, slot,
1597 rank), 9);
1598 train.reg_178 = read_1d0(0x178, 7);
1599 train.reg_10b = read_1d0(0x10b, 6);
1600
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001601 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1602 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001603 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001604 train.reg274265[channel][0] = reg32 >> 16;
1605 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001606 train.reg274265[channel][2] =
1607 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001608 }
Felix Held04be2dd2018-07-29 04:53:22 +02001609 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1610 train.reg_6dc = MCHBAR32(0x6dc);
1611 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612
Arthur Heymansb3282092019-04-14 17:53:28 +02001613 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1614 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001615
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001616 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001617 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1618 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001619}
1620
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621static const struct ram_training *get_cached_training(void)
1622{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001623 struct region_device rdev;
1624 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1625 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001627 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629
1630/* FIXME: add timeout. */
1631static void wait_heci_ready(void)
1632{
Felix Held04be2dd2018-07-29 04:53:22 +02001633 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1634 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001635 write32((DEFAULT_HECIBAR + 0x4),
1636 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637}
1638
1639/* FIXME: add timeout. */
1640static void wait_heci_cb_avail(int len)
1641{
1642 union {
1643 struct mei_csr csr;
1644 u32 raw;
1645 } csr;
1646
Felix Held22ca8cb2018-07-29 05:09:44 +02001647 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1648 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649
1650 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001651 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001652 while (len >
1653 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001654 csr.csr.buffer_read_ptr))
1655 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656}
1657
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001658static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659{
1660 int len = (head->length + 3) / 4;
1661 int i;
1662
1663 wait_heci_cb_avail(len + 1);
1664
1665 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001666 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001668 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001670 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1671 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672}
1673
1674static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001675send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676{
1677 struct mei_header head;
1678 int maxlen;
1679
1680 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001681 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001682
1683 while (len) {
1684 int cur = len;
1685 if (cur > maxlen) {
1686 cur = maxlen;
1687 head.is_complete = 0;
1688 } else
1689 head.is_complete = 1;
1690 head.length = cur;
1691 head.reserved = 0;
1692 head.client_address = clientaddress;
1693 head.host_address = hostaddress;
1694 send_heci_packet(&head, (u32 *) msg);
1695 len -= cur;
1696 msg += cur;
1697 }
1698}
1699
1700/* FIXME: Add timeout. */
1701static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001702recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1703 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704{
1705 union {
1706 struct mei_csr csr;
1707 u32 raw;
1708 } csr;
1709 int i = 0;
1710
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001711 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001712 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001713 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714 }
Felix Held04be2dd2018-07-29 04:53:22 +02001715 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1716 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001717 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001719 write32(DEFAULT_HECIBAR + 0x4,
1720 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001721 *packet_size = 0;
1722 return 0;
1723 }
1724 if (head->length + 4 > 4 * csr.csr.buffer_depth
1725 || head->length > *packet_size) {
1726 *packet_size = 0;
1727 return -1;
1728 }
1729
1730 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001732 while (((head->length + 3) >> 2) >
1733 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1734 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735
1736 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001737 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001738 *packet_size = head->length;
1739 if (!csr.csr.ready)
1740 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001741 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001742 return 0;
1743}
1744
1745/* FIXME: Add timeout. */
1746static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001747recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001748{
1749 struct mei_header head;
1750 int current_position;
1751
1752 current_position = 0;
1753 while (1) {
1754 u32 current_size;
1755 current_size = *message_size - current_position;
1756 if (recv_heci_packet
1757 (info, &head, message + (current_position >> 2),
1758 &current_size) == -1)
1759 break;
1760 if (!current_size)
1761 break;
1762 current_position += current_size;
1763 if (head.is_complete) {
1764 *message_size = current_position;
1765 return 0;
1766 }
1767
1768 if (current_position >= *message_size)
1769 break;
1770 }
1771 *message_size = 0;
1772 return -1;
1773}
1774
1775static void send_heci_uma_message(struct raminfo *info)
1776{
1777 struct uma_reply {
1778 u8 group_id;
1779 u8 command;
1780 u8 reserved;
1781 u8 result;
1782 u8 field2;
1783 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001784 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001785 struct uma_message {
1786 u8 group_id;
1787 u8 cmd;
1788 u8 reserved;
1789 u8 result;
1790 u32 c2;
1791 u64 heci_uma_addr;
1792 u32 memory_reserved_for_heci_mb;
1793 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001794 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001795 0, MKHI_SET_UMA, 0, 0,
1796 0x82,
1797 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1798 u32 reply_size;
1799
1800 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1801
1802 reply_size = sizeof(reply);
1803 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1804 return;
1805
1806 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1807 die("HECI init failed\n");
1808}
1809
1810static void setup_heci_uma(struct raminfo *info)
1811{
1812 u32 reg44;
1813
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001814 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001815 info->memory_reserved_for_heci_mb = 0;
1816 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001817 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001818 return;
1819
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001820 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001821 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1822 info->heci_uma_addr =
1823 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001824 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001825 info->memory_reserved_for_heci_mb)) << 20;
1826
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001827 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001829 write32(DEFAULT_DMIBAR + 0x14,
1830 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1831 write32(DEFAULT_RCBA + 0x14,
1832 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1833 write32(DEFAULT_DMIBAR + 0x20,
1834 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1835 write32(DEFAULT_RCBA + 0x20,
1836 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1837 write32(DEFAULT_DMIBAR + 0x2c,
1838 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1839 write32(DEFAULT_RCBA + 0x30,
1840 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1841 write32(DEFAULT_DMIBAR + 0x38,
1842 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1843 write32(DEFAULT_RCBA + 0x40,
1844 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001845
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001846 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1847 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001848 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1849 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1850 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001851 }
1852
Felix Held04be2dd2018-07-29 04:53:22 +02001853 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001854
1855 send_heci_uma_message(info);
1856
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001857 pci_write_config32(HECIDEV, 0x10, 0x0);
1858 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859
1860}
1861
1862static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1863{
1864 int ranks_in_channel;
1865 ranks_in_channel = info->populated_ranks[channel][0][0]
1866 + info->populated_ranks[channel][0][1]
1867 + info->populated_ranks[channel][1][0]
1868 + info->populated_ranks[channel][1][1];
1869
1870 /* empty channel */
1871 if (ranks_in_channel == 0)
1872 return 1;
1873
1874 if (ranks_in_channel != ranks)
1875 return 0;
1876 /* single slot */
1877 if (info->populated_ranks[channel][0][0] !=
1878 info->populated_ranks[channel][1][0])
1879 return 1;
1880 if (info->populated_ranks[channel][0][1] !=
1881 info->populated_ranks[channel][1][1])
1882 return 1;
1883 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1884 return 0;
1885 if (info->density[channel][0] != info->density[channel][1])
1886 return 0;
1887 return 1;
1888}
1889
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001890static void read_4090(struct raminfo *info)
1891{
1892 int i, channel, slot, rank, lane;
1893 for (i = 0; i < 2; i++)
1894 for (slot = 0; slot < NUM_SLOTS; slot++)
1895 for (rank = 0; rank < NUM_RANKS; rank++)
1896 for (lane = 0; lane < 9; lane++)
1897 info->training.
1898 lane_timings[0][i][slot][rank][lane]
1899 = 32;
1900
1901 for (i = 1; i < 4; i++)
1902 for (channel = 0; channel < NUM_CHANNELS; channel++)
1903 for (slot = 0; slot < NUM_SLOTS; slot++)
1904 for (rank = 0; rank < NUM_RANKS; rank++)
1905 for (lane = 0; lane < 9; lane++) {
1906 info->training.
1907 lane_timings[i][channel]
1908 [slot][rank][lane] =
1909 read_500(info, channel,
1910 get_timing_register_addr
1911 (lane, i, slot,
1912 rank), 9)
1913 + (i == 1) * 11; // !!!!
1914 }
1915
1916}
1917
1918static u32 get_etalon2(int flip, u32 addr)
1919{
1920 const u16 invmask[] = {
1921 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1922 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1923 };
1924 u32 ret;
1925 u32 comp4 = addr / 480;
1926 addr %= 480;
1927 u32 comp1 = addr & 0xf;
1928 u32 comp2 = (addr >> 4) & 1;
1929 u32 comp3 = addr >> 5;
1930
1931 if (comp4)
1932 ret = 0x1010101 << (comp4 - 1);
1933 else
1934 ret = 0;
1935 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1936 ret = ~ret;
1937
1938 return ret;
1939}
1940
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001941static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001942{
1943 msr_t msr = {.lo = 0, .hi = 0 };
1944
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001945 wrmsr(MTRR_PHYS_BASE(3), msr);
1946 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001947}
1948
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001949static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001950{
1951 msr_t msr;
1952 msr.lo = base | MTRR_TYPE_WRPROT;
1953 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001954 wrmsr(MTRR_PHYS_BASE(3), msr);
1955 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001956 & 0xffffffff);
1957 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001958 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001959}
1960
1961static void flush_cache(u32 start, u32 size)
1962{
1963 u32 end;
1964 u32 addr;
1965
1966 end = start + (ALIGN_DOWN(size + 4096, 4096));
1967 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001968 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969}
1970
1971static void clear_errors(void)
1972{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001973 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001974}
1975
1976static void write_testing(struct raminfo *info, int totalrank, int flip)
1977{
1978 int nwrites = 0;
1979 /* in 8-byte units. */
1980 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001981 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001982
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001983 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001984 for (offset = 0; offset < 9 * 480; offset += 2) {
1985 write32(base + offset * 8, get_etalon2(flip, offset));
1986 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1987 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1988 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1989 nwrites += 4;
1990 if (nwrites >= 320) {
1991 clear_errors();
1992 nwrites = 0;
1993 }
1994 }
1995}
1996
1997static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1998{
1999 u8 failmask = 0;
2000 int i;
2001 int comp1, comp2, comp3;
2002 u32 failxor[2] = { 0, 0 };
2003
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002004 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002005
2006 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2007 for (comp1 = 0; comp1 < 4; comp1++)
2008 for (comp2 = 0; comp2 < 60; comp2++) {
2009 u32 re[4];
2010 u32 curroffset =
2011 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2012 read128((total_rank << 28) | (curroffset << 3),
2013 (u64 *) re);
2014 failxor[0] |=
2015 get_etalon2(flip, curroffset) ^ re[0];
2016 failxor[1] |=
2017 get_etalon2(flip, curroffset) ^ re[1];
2018 failxor[0] |=
2019 get_etalon2(flip, curroffset | 1) ^ re[2];
2020 failxor[1] |=
2021 get_etalon2(flip, curroffset | 1) ^ re[3];
2022 }
2023 for (i = 0; i < 8; i++)
2024 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2025 failmask |= 1 << i;
2026 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002027 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002028 flush_cache((total_rank << 28), 1728 * 5 * 4);
2029 return failmask;
2030}
2031
2032const u32 seed1[0x18] = {
2033 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2034 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2035 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2036 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2037 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2038 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2039};
2040
2041static u32 get_seed2(int a, int b)
2042{
2043 const u32 seed2[5] = {
2044 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2045 0x5b6db6db,
2046 };
2047 u32 r;
2048 r = seed2[(a + (a >= 10)) / 5];
2049 return b ? ~r : r;
2050}
2051
2052static int make_shift(int comp2, int comp5, int x)
2053{
2054 const u8 seed3[32] = {
2055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2056 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2057 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2058 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2059 };
2060
2061 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2062}
2063
2064static u32 get_etalon(int flip, u32 addr)
2065{
2066 u32 mask_byte = 0;
2067 int comp1 = (addr >> 1) & 1;
2068 int comp2 = (addr >> 3) & 0x1f;
2069 int comp3 = (addr >> 8) & 0xf;
2070 int comp4 = (addr >> 12) & 0xf;
2071 int comp5 = (addr >> 16) & 0x1f;
2072 u32 mask_bit = ~(0x10001 << comp3);
2073 u32 part1;
2074 u32 part2;
2075 int byte;
2076
2077 part2 =
2078 ((seed1[comp5] >>
2079 make_shift(comp2, comp5,
2080 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2081 part1 =
2082 ((seed1[comp5] >>
2083 make_shift(comp2, comp5,
2084 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2085
2086 for (byte = 0; byte < 4; byte++)
2087 if ((get_seed2(comp5, comp4) >>
2088 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2089 mask_byte |= 0xff << (8 * byte);
2090
2091 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2092 (comp3 + 16));
2093}
2094
2095static void
2096write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2097 char flip)
2098{
2099 int i;
2100 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002101 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2102 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002103}
2104
2105static u8
2106check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2107 char flip)
2108{
2109 u8 failmask = 0;
2110 u32 failxor[2];
2111 int i;
2112 int comp1, comp2, comp3;
2113
2114 failxor[0] = 0;
2115 failxor[1] = 0;
2116
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002117 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002118 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2119 for (comp1 = 0; comp1 < 16; comp1++)
2120 for (comp2 = 0; comp2 < 64; comp2++) {
2121 u32 addr =
2122 (totalrank << 28) | (region << 25) | (block
2123 << 16)
2124 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2125 2);
2126 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002127 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002128 }
2129 for (i = 0; i < 8; i++)
2130 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2131 failmask |= 1 << i;
2132 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002133 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002134 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2135 return failmask;
2136}
2137
2138static int check_bounded(unsigned short *vals, u16 bound)
2139{
2140 int i;
2141
2142 for (i = 0; i < 8; i++)
2143 if (vals[i] < bound)
2144 return 0;
2145 return 1;
2146}
2147
2148enum state {
2149 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2150};
2151
2152static int validate_state(enum state *in)
2153{
2154 int i;
2155 for (i = 0; i < 8; i++)
2156 if (in[i] != COMPLETE)
2157 return 0;
2158 return 1;
2159}
2160
2161static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002162do_fsm(enum state *state, u16 *counter,
2163 u8 fail_mask, int margin, int uplimit,
2164 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002165{
2166 int lane;
2167
2168 for (lane = 0; lane < 8; lane++) {
2169 int is_fail = (fail_mask >> lane) & 1;
2170 switch (state[lane]) {
2171 case BEFORE_USABLE:
2172 if (!is_fail) {
2173 counter[lane] = 1;
2174 state[lane] = AT_USABLE;
2175 break;
2176 }
2177 counter[lane] = 0;
2178 state[lane] = BEFORE_USABLE;
2179 break;
2180 case AT_USABLE:
2181 if (!is_fail) {
2182 ++counter[lane];
2183 if (counter[lane] >= margin) {
2184 state[lane] = AT_MARGIN;
2185 res_low[lane] = val - margin + 1;
2186 break;
2187 }
2188 state[lane] = 1;
2189 break;
2190 }
2191 counter[lane] = 0;
2192 state[lane] = BEFORE_USABLE;
2193 break;
2194 case AT_MARGIN:
2195 if (is_fail) {
2196 state[lane] = COMPLETE;
2197 res_high[lane] = val - 1;
2198 } else {
2199 counter[lane]++;
2200 state[lane] = AT_MARGIN;
2201 if (val == uplimit) {
2202 state[lane] = COMPLETE;
2203 res_high[lane] = uplimit;
2204 }
2205 }
2206 break;
2207 case COMPLETE:
2208 break;
2209 }
2210 }
2211}
2212
2213static void
2214train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2215 u8 total_rank, u8 reg_178, int first_run, int niter,
2216 timing_bounds_t * timings)
2217{
2218 int lane;
2219 enum state state[8];
2220 u16 count[8];
2221 u8 lower_usable[8];
2222 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002223 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002224 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002225 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002226
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002227 for (i = 0; i < 8; i++)
2228 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002229
2230 if (!first_run) {
2231 int is_all_ok = 1;
2232 for (lane = 0; lane < 8; lane++)
2233 if (timings[reg_178][channel][slot][rank][lane].
2234 smallest ==
2235 timings[reg_178][channel][slot][rank][lane].
2236 largest) {
2237 timings[reg_178][channel][slot][rank][lane].
2238 smallest = 0;
2239 timings[reg_178][channel][slot][rank][lane].
2240 largest = 0;
2241 is_all_ok = 0;
2242 }
2243 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002244 for (i = 0; i < 8; i++)
2245 state[i] = COMPLETE;
2246 }
2247 }
2248
2249 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2250 u8 failmask = 0;
2251 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2252 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2253 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002254 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002255 do_fsm(state, count, failmask, 5, 47, lower_usable,
2256 upper_usable, reg1b3);
2257 }
2258
2259 if (reg1b3) {
2260 write_1d0(0, 0x1b3, 6, 1);
2261 write_1d0(0, 0x1a3, 6, 1);
2262 for (lane = 0; lane < 8; lane++) {
2263 if (state[lane] == COMPLETE) {
2264 timings[reg_178][channel][slot][rank][lane].
2265 smallest =
2266 lower_usable[lane] +
2267 (info->training.
2268 lane_timings[0][channel][slot][rank][lane]
2269 & 0x3F) - 32;
2270 timings[reg_178][channel][slot][rank][lane].
2271 largest =
2272 upper_usable[lane] +
2273 (info->training.
2274 lane_timings[0][channel][slot][rank][lane]
2275 & 0x3F) - 32;
2276 }
2277 }
2278 }
2279
2280 if (!first_run) {
2281 for (lane = 0; lane < 8; lane++)
2282 if (state[lane] == COMPLETE) {
2283 write_500(info, channel,
2284 timings[reg_178][channel][slot][rank]
2285 [lane].smallest,
2286 get_timing_register_addr(lane, 0,
2287 slot, rank),
2288 9, 1);
2289 write_500(info, channel,
2290 timings[reg_178][channel][slot][rank]
2291 [lane].smallest +
2292 info->training.
2293 lane_timings[1][channel][slot][rank]
2294 [lane]
2295 -
2296 info->training.
2297 lane_timings[0][channel][slot][rank]
2298 [lane], get_timing_register_addr(lane,
2299 1,
2300 slot,
2301 rank),
2302 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002303 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002304 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306
2307 do {
2308 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002309 for (i = 0; i < niter; i++) {
2310 if (failmask == 0xFF)
2311 break;
2312 failmask |=
2313 check_testing_type2(info, total_rank, 2, i,
2314 0);
2315 failmask |=
2316 check_testing_type2(info, total_rank, 3, i,
2317 1);
2318 }
Felix Held04be2dd2018-07-29 04:53:22 +02002319 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002320 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002321 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 if ((1 << lane) & failmask) {
2323 if (timings[reg_178][channel]
2324 [slot][rank][lane].
2325 largest <=
2326 timings[reg_178][channel]
2327 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002328 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002329 [lane] = -1;
2330 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002331 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002332 [lane] = 0;
2333 timings[reg_178]
2334 [channel][slot]
2335 [rank][lane].
2336 smallest++;
2337 write_500(info, channel,
2338 timings
2339 [reg_178]
2340 [channel]
2341 [slot][rank]
2342 [lane].
2343 smallest,
2344 get_timing_register_addr
2345 (lane, 0,
2346 slot, rank),
2347 9, 1);
2348 write_500(info, channel,
2349 timings
2350 [reg_178]
2351 [channel]
2352 [slot][rank]
2353 [lane].
2354 smallest +
2355 info->
2356 training.
2357 lane_timings
2358 [1][channel]
2359 [slot][rank]
2360 [lane]
2361 -
2362 info->
2363 training.
2364 lane_timings
2365 [0][channel]
2366 [slot][rank]
2367 [lane],
2368 get_timing_register_addr
2369 (lane, 1,
2370 slot, rank),
2371 9, 1);
2372 }
2373 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002374 num_successfully_checked[lane]
2375 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002376 }
2377 }
Felix Held04be2dd2018-07-29 04:53:22 +02002378 while (!check_bounded(num_successfully_checked, 2))
2379 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380
2381 for (lane = 0; lane < 8; lane++)
2382 if (state[lane] == COMPLETE) {
2383 write_500(info, channel,
2384 timings[reg_178][channel][slot][rank]
2385 [lane].largest,
2386 get_timing_register_addr(lane, 0,
2387 slot, rank),
2388 9, 1);
2389 write_500(info, channel,
2390 timings[reg_178][channel][slot][rank]
2391 [lane].largest +
2392 info->training.
2393 lane_timings[1][channel][slot][rank]
2394 [lane]
2395 -
2396 info->training.
2397 lane_timings[0][channel][slot][rank]
2398 [lane], get_timing_register_addr(lane,
2399 1,
2400 slot,
2401 rank),
2402 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002403 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002404 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002405 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002406
2407 do {
2408 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002409 for (i = 0; i < niter; i++) {
2410 if (failmask == 0xFF)
2411 break;
2412 failmask |=
2413 check_testing_type2(info, total_rank, 2, i,
2414 0);
2415 failmask |=
2416 check_testing_type2(info, total_rank, 3, i,
2417 1);
2418 }
2419
Felix Held04be2dd2018-07-29 04:53:22 +02002420 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002422 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423 if ((1 << lane) & failmask) {
2424 if (timings[reg_178][channel]
2425 [slot][rank][lane].
2426 largest <=
2427 timings[reg_178][channel]
2428 [slot][rank][lane].
2429 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002430 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002431 [lane] = -1;
2432 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002433 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434 [lane] = 0;
2435 timings[reg_178]
2436 [channel][slot]
2437 [rank][lane].
2438 largest--;
2439 write_500(info, channel,
2440 timings
2441 [reg_178]
2442 [channel]
2443 [slot][rank]
2444 [lane].
2445 largest,
2446 get_timing_register_addr
2447 (lane, 0,
2448 slot, rank),
2449 9, 1);
2450 write_500(info, channel,
2451 timings
2452 [reg_178]
2453 [channel]
2454 [slot][rank]
2455 [lane].
2456 largest +
2457 info->
2458 training.
2459 lane_timings
2460 [1][channel]
2461 [slot][rank]
2462 [lane]
2463 -
2464 info->
2465 training.
2466 lane_timings
2467 [0][channel]
2468 [slot][rank]
2469 [lane],
2470 get_timing_register_addr
2471 (lane, 1,
2472 slot, rank),
2473 9, 1);
2474 }
2475 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002476 num_successfully_checked[lane]
2477 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002478 }
2479 }
2480 }
Felix Held04be2dd2018-07-29 04:53:22 +02002481 while (!check_bounded(num_successfully_checked, 3))
2482 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002483
2484 for (lane = 0; lane < 8; lane++) {
2485 write_500(info, channel,
2486 info->training.
2487 lane_timings[0][channel][slot][rank][lane],
2488 get_timing_register_addr(lane, 0, slot, rank),
2489 9, 1);
2490 write_500(info, channel,
2491 info->training.
2492 lane_timings[1][channel][slot][rank][lane],
2493 get_timing_register_addr(lane, 1, slot, rank),
2494 9, 1);
2495 if (timings[reg_178][channel][slot][rank][lane].
2496 largest <=
2497 timings[reg_178][channel][slot][rank][lane].
2498 smallest) {
2499 timings[reg_178][channel][slot][rank][lane].
2500 largest = 0;
2501 timings[reg_178][channel][slot][rank][lane].
2502 smallest = 0;
2503 }
2504 }
2505 }
2506}
2507
2508static void set_10b(struct raminfo *info, u8 val)
2509{
2510 int channel;
2511 int slot, rank;
2512 int lane;
2513
2514 if (read_1d0(0x10b, 6) == val)
2515 return;
2516
2517 write_1d0(val, 0x10b, 6, 1);
2518
2519 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2520 u16 reg_500;
2521 reg_500 = read_500(info, channel,
2522 get_timing_register_addr(lane, 0, slot,
2523 rank), 9);
2524 if (val == 1) {
2525 if (lut16[info->clock_speed_index] <= reg_500)
2526 reg_500 -= lut16[info->clock_speed_index];
2527 else
2528 reg_500 = 0;
2529 } else {
2530 reg_500 += lut16[info->clock_speed_index];
2531 }
2532 write_500(info, channel, reg_500,
2533 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2534 }
2535}
2536
2537static void set_ecc(int onoff)
2538{
2539 int channel;
2540 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2541 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002542 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002543 if (onoff)
2544 t |= 1;
2545 else
2546 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002547 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002548 }
2549}
2550
2551static void set_178(u8 val)
2552{
2553 if (val >= 31)
2554 val = val - 31;
2555 else
2556 val = 63 - val;
2557
2558 write_1d0(2 * val, 0x178, 7, 1);
2559}
2560
2561static void
2562write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2563 int type)
2564{
2565 int lane;
2566
2567 for (lane = 0; lane < 8; lane++)
2568 write_500(info, channel,
2569 info->training.
2570 lane_timings[type][channel][slot][rank][lane],
2571 get_timing_register_addr(lane, type, slot, rank), 9,
2572 0);
2573}
2574
2575static void
2576try_timing_offsets(struct raminfo *info, int channel,
2577 int slot, int rank, int totalrank)
2578{
2579 u16 count[8];
2580 enum state state[8];
2581 u8 lower_usable[8], upper_usable[8];
2582 int lane;
2583 int i;
2584 int flip = 1;
2585 int timing_offset;
2586
2587 for (i = 0; i < 8; i++)
2588 state[i] = BEFORE_USABLE;
2589
2590 memset(count, 0, sizeof(count));
2591
2592 for (lane = 0; lane < 8; lane++)
2593 write_500(info, channel,
2594 info->training.
2595 lane_timings[2][channel][slot][rank][lane] + 32,
2596 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2597
2598 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2599 timing_offset++) {
2600 u8 failmask;
2601 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2602 failmask = 0;
2603 for (i = 0; i < 2 && failmask != 0xff; i++) {
2604 flip = !flip;
2605 write_testing(info, totalrank, flip);
2606 failmask |= check_testing(info, totalrank, flip);
2607 }
2608 do_fsm(state, count, failmask, 10, 63, lower_usable,
2609 upper_usable, timing_offset);
2610 }
2611 write_1d0(0, 0x1bb, 6, 1);
2612 dump_timings(info);
2613 if (!validate_state(state))
2614 die("Couldn't discover DRAM timings (1)\n");
2615
2616 for (lane = 0; lane < 8; lane++) {
2617 u8 bias = 0;
2618
2619 if (info->silicon_revision) {
2620 int usable_length;
2621
2622 usable_length = upper_usable[lane] - lower_usable[lane];
2623 if (usable_length >= 20) {
2624 bias = usable_length / 2 - 10;
2625 if (bias >= 2)
2626 bias = 2;
2627 }
2628 }
2629 write_500(info, channel,
2630 info->training.
2631 lane_timings[2][channel][slot][rank][lane] +
2632 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2633 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2634 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2635 info->training.lane_timings[2][channel][slot][rank][lane] +
2636 lower_usable[lane];
2637 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2638 info->training.lane_timings[2][channel][slot][rank][lane] +
2639 upper_usable[lane];
2640 info->training.timing2_offset[channel][slot][rank][lane] =
2641 info->training.lane_timings[2][channel][slot][rank][lane];
2642 }
2643}
2644
2645static u8
2646choose_training(struct raminfo *info, int channel, int slot, int rank,
2647 int lane, timing_bounds_t * timings, u8 center_178)
2648{
2649 u16 central_weight;
2650 u16 side_weight;
2651 unsigned int sum = 0, count = 0;
2652 u8 span;
2653 u8 lower_margin, upper_margin;
2654 u8 reg_178;
2655 u8 result;
2656
2657 span = 12;
2658 central_weight = 20;
2659 side_weight = 20;
2660 if (info->silicon_revision == 1 && channel == 1) {
2661 central_weight = 5;
2662 side_weight = 20;
2663 if ((info->
2664 populated_ranks_mask[1] ^ (info->
2665 populated_ranks_mask[1] >> 2)) &
2666 1)
2667 span = 18;
2668 }
2669 if ((info->populated_ranks_mask[0] & 5) == 5) {
2670 central_weight = 20;
2671 side_weight = 20;
2672 }
2673 if (info->clock_speed_index >= 2
2674 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2675 if (info->silicon_revision == 1) {
2676 switch (channel) {
2677 case 0:
2678 if (lane == 1) {
2679 central_weight = 10;
2680 side_weight = 20;
2681 }
2682 break;
2683 case 1:
2684 if (lane == 6) {
2685 side_weight = 5;
2686 central_weight = 20;
2687 }
2688 break;
2689 }
2690 }
2691 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2692 side_weight = 5;
2693 central_weight = 20;
2694 }
2695 }
2696 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2697 reg_178 += span) {
2698 u8 smallest;
2699 u8 largest;
2700 largest = timings[reg_178][channel][slot][rank][lane].largest;
2701 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2702 if (largest - smallest + 1 >= 5) {
2703 unsigned int weight;
2704 if (reg_178 == center_178)
2705 weight = central_weight;
2706 else
2707 weight = side_weight;
2708 sum += weight * (largest + smallest);
2709 count += weight;
2710 }
2711 }
2712 dump_timings(info);
2713 if (count == 0)
2714 die("Couldn't discover DRAM timings (2)\n");
2715 result = sum / (2 * count);
2716 lower_margin =
2717 result - timings[center_178][channel][slot][rank][lane].smallest;
2718 upper_margin =
2719 timings[center_178][channel][slot][rank][lane].largest - result;
2720 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002721 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002722 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002723 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002724 return result;
2725}
2726
2727#define STANDARD_MIN_MARGIN 5
2728
2729static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2730{
2731 u16 margin[64];
2732 int lane, rank, slot, channel;
2733 u8 reg178;
2734 int count = 0, sum = 0;
2735
2736 for (reg178 = reg178_min[info->clock_speed_index];
2737 reg178 < reg178_max[info->clock_speed_index];
2738 reg178 += reg178_step[info->clock_speed_index]) {
2739 margin[reg178] = -1;
2740 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2741 int curmargin =
2742 timings[reg178][channel][slot][rank][lane].largest -
2743 timings[reg178][channel][slot][rank][lane].
2744 smallest + 1;
2745 if (curmargin < margin[reg178])
2746 margin[reg178] = curmargin;
2747 }
2748 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2749 u16 weight;
2750 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2751 sum += weight * reg178;
2752 count += weight;
2753 }
2754 }
2755 dump_timings(info);
2756 if (count == 0)
2757 die("Couldn't discover DRAM timings (3)\n");
2758
2759 u8 threshold;
2760
2761 for (threshold = 30; threshold >= 5; threshold--) {
2762 int usable_length = 0;
2763 int smallest_fount = 0;
2764 for (reg178 = reg178_min[info->clock_speed_index];
2765 reg178 < reg178_max[info->clock_speed_index];
2766 reg178 += reg178_step[info->clock_speed_index])
2767 if (margin[reg178] >= threshold) {
2768 usable_length +=
2769 reg178_step[info->clock_speed_index];
2770 info->training.reg178_largest =
2771 reg178 -
2772 2 * reg178_step[info->clock_speed_index];
2773
2774 if (!smallest_fount) {
2775 smallest_fount = 1;
2776 info->training.reg178_smallest =
2777 reg178 +
2778 reg178_step[info->
2779 clock_speed_index];
2780 }
2781 }
2782 if (usable_length >= 0x21)
2783 break;
2784 }
2785
2786 return sum / count;
2787}
2788
2789static int check_cached_sanity(struct raminfo *info)
2790{
2791 int lane;
2792 int slot, rank;
2793 int channel;
2794
2795 if (!info->cached_training)
2796 return 0;
2797
2798 for (channel = 0; channel < NUM_CHANNELS; channel++)
2799 for (slot = 0; slot < NUM_SLOTS; slot++)
2800 for (rank = 0; rank < NUM_RANKS; rank++)
2801 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2802 u16 cached_value, estimation_value;
2803 cached_value =
2804 info->cached_training->
2805 lane_timings[1][channel][slot][rank]
2806 [lane];
2807 if (cached_value >= 0x18
2808 && cached_value <= 0x1E7) {
2809 estimation_value =
2810 info->training.
2811 lane_timings[1][channel]
2812 [slot][rank][lane];
2813 if (estimation_value <
2814 cached_value - 24)
2815 return 0;
2816 if (estimation_value >
2817 cached_value + 24)
2818 return 0;
2819 }
2820 }
2821 return 1;
2822}
2823
2824static int try_cached_training(struct raminfo *info)
2825{
2826 u8 saved_243[2];
2827 u8 tm;
2828
2829 int channel, slot, rank, lane;
2830 int flip = 1;
2831 int i, j;
2832
2833 if (!check_cached_sanity(info))
2834 return 0;
2835
2836 info->training.reg178_center = info->cached_training->reg178_center;
2837 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2838 info->training.reg178_largest = info->cached_training->reg178_largest;
2839 memcpy(&info->training.timing_bounds,
2840 &info->cached_training->timing_bounds,
2841 sizeof(info->training.timing_bounds));
2842 memcpy(&info->training.timing_offset,
2843 &info->cached_training->timing_offset,
2844 sizeof(info->training.timing_offset));
2845
2846 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002847 saved_243[0] = MCHBAR8(0x243);
2848 saved_243[1] = MCHBAR8(0x643);
2849 MCHBAR8(0x243) = saved_243[0] | 2;
2850 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002851 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002852 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002853 if (read_1d0(0x10b, 6) & 1)
2854 set_10b(info, 0);
2855 for (tm = 0; tm < 2; tm++) {
2856 int totalrank;
2857
2858 set_178(tm ? info->cached_training->reg178_largest : info->
2859 cached_training->reg178_smallest);
2860
2861 totalrank = 0;
2862 /* Check timing ranges. With i == 0 we check smallest one and with
2863 i == 1 the largest bound. With j == 0 we check that on the bound
2864 it still works whereas with j == 1 we check that just outside of
2865 bound we fail.
2866 */
2867 FOR_POPULATED_RANKS_BACKWARDS {
2868 for (i = 0; i < 2; i++) {
2869 for (lane = 0; lane < 8; lane++) {
2870 write_500(info, channel,
2871 info->cached_training->
2872 timing2_bounds[channel][slot]
2873 [rank][lane][i],
2874 get_timing_register_addr(lane,
2875 3,
2876 slot,
2877 rank),
2878 9, 1);
2879
2880 if (!i)
2881 write_500(info, channel,
2882 info->
2883 cached_training->
2884 timing2_offset
2885 [channel][slot][rank]
2886 [lane],
2887 get_timing_register_addr
2888 (lane, 2, slot, rank),
2889 9, 1);
2890 write_500(info, channel,
2891 i ? info->cached_training->
2892 timing_bounds[tm][channel]
2893 [slot][rank][lane].
2894 largest : info->
2895 cached_training->
2896 timing_bounds[tm][channel]
2897 [slot][rank][lane].smallest,
2898 get_timing_register_addr(lane,
2899 0,
2900 slot,
2901 rank),
2902 9, 1);
2903 write_500(info, channel,
2904 info->cached_training->
2905 timing_offset[channel][slot]
2906 [rank][lane] +
2907 (i ? info->cached_training->
2908 timing_bounds[tm][channel]
2909 [slot][rank][lane].
2910 largest : info->
2911 cached_training->
2912 timing_bounds[tm][channel]
2913 [slot][rank][lane].
2914 smallest) - 64,
2915 get_timing_register_addr(lane,
2916 1,
2917 slot,
2918 rank),
2919 9, 1);
2920 }
2921 for (j = 0; j < 2; j++) {
2922 u8 failmask;
2923 u8 expected_failmask;
2924 char reg1b3;
2925
2926 reg1b3 = (j == 1) + 4;
2927 reg1b3 =
2928 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2929 write_1d0(reg1b3, 0x1bb, 6, 1);
2930 write_1d0(reg1b3, 0x1b3, 6, 1);
2931 write_1d0(reg1b3, 0x1a3, 6, 1);
2932
2933 flip = !flip;
2934 write_testing(info, totalrank, flip);
2935 failmask =
2936 check_testing(info, totalrank,
2937 flip);
2938 expected_failmask =
2939 j == 0 ? 0x00 : 0xff;
2940 if (failmask != expected_failmask)
2941 goto fail;
2942 }
2943 }
2944 totalrank++;
2945 }
2946 }
2947
2948 set_178(info->cached_training->reg178_center);
2949 if (info->use_ecc)
2950 set_ecc(1);
2951 write_training_data(info);
2952 write_1d0(0, 322, 3, 1);
2953 info->training = *info->cached_training;
2954
2955 write_1d0(0, 0x1bb, 6, 1);
2956 write_1d0(0, 0x1b3, 6, 1);
2957 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002958 MCHBAR8(0x243) = saved_243[0];
2959 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002960
2961 return 1;
2962
2963fail:
2964 FOR_POPULATED_RANKS {
2965 write_500_timings_type(info, channel, slot, rank, 1);
2966 write_500_timings_type(info, channel, slot, rank, 2);
2967 write_500_timings_type(info, channel, slot, rank, 3);
2968 }
2969
2970 write_1d0(0, 0x1bb, 6, 1);
2971 write_1d0(0, 0x1b3, 6, 1);
2972 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002973 MCHBAR8(0x243) = saved_243[0];
2974 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002975
2976 return 0;
2977}
2978
2979static void do_ram_training(struct raminfo *info)
2980{
2981 u8 saved_243[2];
2982 int totalrank = 0;
2983 u8 reg_178;
2984 int niter;
2985
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002986 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002987 int lane, rank, slot, channel;
2988 u8 reg178_center;
2989
2990 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002991 saved_243[0] = MCHBAR8(0x243);
2992 saved_243[1] = MCHBAR8(0x643);
2993 MCHBAR8(0x243) = saved_243[0] | 2;
2994 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002995 switch (info->clock_speed_index) {
2996 case 0:
2997 niter = 5;
2998 break;
2999 case 1:
3000 niter = 10;
3001 break;
3002 default:
3003 niter = 19;
3004 break;
3005 }
3006 set_ecc(0);
3007
3008 FOR_POPULATED_RANKS_BACKWARDS {
3009 int i;
3010
3011 write_500_timings_type(info, channel, slot, rank, 0);
3012
3013 write_testing(info, totalrank, 0);
3014 for (i = 0; i < niter; i++) {
3015 write_testing_type2(info, totalrank, 2, i, 0);
3016 write_testing_type2(info, totalrank, 3, i, 1);
3017 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003018 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003019 totalrank++;
3020 }
3021
3022 if (reg178_min[info->clock_speed_index] <
3023 reg178_max[info->clock_speed_index])
3024 memset(timings[reg178_min[info->clock_speed_index]], 0,
3025 sizeof(timings[0]) *
3026 (reg178_max[info->clock_speed_index] -
3027 reg178_min[info->clock_speed_index]));
3028 for (reg_178 = reg178_min[info->clock_speed_index];
3029 reg_178 < reg178_max[info->clock_speed_index];
3030 reg_178 += reg178_step[info->clock_speed_index]) {
3031 totalrank = 0;
3032 set_178(reg_178);
3033 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3034 for (slot = 0; slot < NUM_SLOTS; slot++)
3035 for (rank = 0; rank < NUM_RANKS; rank++) {
3036 memset(&timings[reg_178][channel][slot]
3037 [rank][0].smallest, 0, 16);
3038 if (info->
3039 populated_ranks[channel][slot]
3040 [rank]) {
3041 train_ram_at_178(info, channel,
3042 slot, rank,
3043 totalrank,
3044 reg_178, 1,
3045 niter,
3046 timings);
3047 totalrank++;
3048 }
3049 }
3050 }
3051
3052 reg178_center = choose_reg178(info, timings);
3053
3054 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3055 info->training.timing_bounds[0][channel][slot][rank][lane].
3056 smallest =
3057 timings[info->training.
3058 reg178_smallest][channel][slot][rank][lane].
3059 smallest;
3060 info->training.timing_bounds[0][channel][slot][rank][lane].
3061 largest =
3062 timings[info->training.
3063 reg178_smallest][channel][slot][rank][lane].largest;
3064 info->training.timing_bounds[1][channel][slot][rank][lane].
3065 smallest =
3066 timings[info->training.
3067 reg178_largest][channel][slot][rank][lane].smallest;
3068 info->training.timing_bounds[1][channel][slot][rank][lane].
3069 largest =
3070 timings[info->training.
3071 reg178_largest][channel][slot][rank][lane].largest;
3072 info->training.timing_offset[channel][slot][rank][lane] =
3073 info->training.lane_timings[1][channel][slot][rank][lane]
3074 -
3075 info->training.lane_timings[0][channel][slot][rank][lane] +
3076 64;
3077 }
3078
3079 if (info->silicon_revision == 1
3080 && (info->
3081 populated_ranks_mask[1] ^ (info->
3082 populated_ranks_mask[1] >> 2)) & 1) {
3083 int ranks_after_channel1;
3084
3085 totalrank = 0;
3086 for (reg_178 = reg178_center - 18;
3087 reg_178 <= reg178_center + 18; reg_178 += 18) {
3088 totalrank = 0;
3089 set_178(reg_178);
3090 for (slot = 0; slot < NUM_SLOTS; slot++)
3091 for (rank = 0; rank < NUM_RANKS; rank++) {
3092 if (info->
3093 populated_ranks[1][slot][rank]) {
3094 train_ram_at_178(info, 1, slot,
3095 rank,
3096 totalrank,
3097 reg_178, 0,
3098 niter,
3099 timings);
3100 totalrank++;
3101 }
3102 }
3103 }
3104 ranks_after_channel1 = totalrank;
3105
3106 for (reg_178 = reg178_center - 12;
3107 reg_178 <= reg178_center + 12; reg_178 += 12) {
3108 totalrank = ranks_after_channel1;
3109 set_178(reg_178);
3110 for (slot = 0; slot < NUM_SLOTS; slot++)
3111 for (rank = 0; rank < NUM_RANKS; rank++)
3112 if (info->
3113 populated_ranks[0][slot][rank]) {
3114 train_ram_at_178(info, 0, slot,
3115 rank,
3116 totalrank,
3117 reg_178, 0,
3118 niter,
3119 timings);
3120 totalrank++;
3121 }
3122
3123 }
3124 } else {
3125 for (reg_178 = reg178_center - 12;
3126 reg_178 <= reg178_center + 12; reg_178 += 12) {
3127 totalrank = 0;
3128 set_178(reg_178);
3129 FOR_POPULATED_RANKS_BACKWARDS {
3130 train_ram_at_178(info, channel, slot, rank,
3131 totalrank, reg_178, 0, niter,
3132 timings);
3133 totalrank++;
3134 }
3135 }
3136 }
3137
3138 set_178(reg178_center);
3139 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3140 u16 tm0;
3141
3142 tm0 =
3143 choose_training(info, channel, slot, rank, lane, timings,
3144 reg178_center);
3145 write_500(info, channel, tm0,
3146 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3147 write_500(info, channel,
3148 tm0 +
3149 info->training.
3150 lane_timings[1][channel][slot][rank][lane] -
3151 info->training.
3152 lane_timings[0][channel][slot][rank][lane],
3153 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3154 }
3155
3156 totalrank = 0;
3157 FOR_POPULATED_RANKS_BACKWARDS {
3158 try_timing_offsets(info, channel, slot, rank, totalrank);
3159 totalrank++;
3160 }
Felix Held04be2dd2018-07-29 04:53:22 +02003161 MCHBAR8(0x243) = saved_243[0];
3162 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003163 write_1d0(0, 0x142, 3, 1);
3164 info->training.reg178_center = reg178_center;
3165}
3166
3167static void ram_training(struct raminfo *info)
3168{
3169 u16 saved_fc4;
3170
Felix Held04be2dd2018-07-29 04:53:22 +02003171 saved_fc4 = MCHBAR16(0xfc4);
3172 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003173
3174 if (info->revision >= 8)
3175 read_4090(info);
3176
3177 if (!try_cached_training(info))
3178 do_ram_training(info);
3179 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3180 && info->clock_speed_index < 2)
3181 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003182 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003183}
3184
Martin Roth468d02c2019-10-23 21:44:42 -06003185static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003186{
Martin Roth468d02c2019-10-23 21:44:42 -06003187 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003188 if (a > b) {
3189 t = a;
3190 a = b;
3191 b = t;
3192 }
3193 /* invariant a < b. */
3194 while (a) {
3195 t = b % a;
3196 b = a;
3197 a = t;
3198 }
3199 return b;
3200}
3201
3202static inline int div_roundup(int a, int b)
3203{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003204 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003205}
3206
Martin Roth468d02c2019-10-23 21:44:42 -06003207static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003208{
3209 return (a * b) / gcd(a, b);
3210}
3211
3212struct stru1 {
3213 u8 freqs_reversed;
3214 u8 freq_diff_reduced;
3215 u8 freq_min_reduced;
3216 u8 divisor_f4_to_fmax;
3217 u8 divisor_f3_to_fmax;
3218 u8 freq4_to_max_remainder;
3219 u8 freq3_to_2_remainder;
3220 u8 freq3_to_2_remaindera;
3221 u8 freq4_to_2_remainder;
3222 int divisor_f3_to_f1, divisor_f4_to_f2;
3223 int common_time_unit_ps;
3224 int freq_max_reduced;
3225};
3226
3227static void
3228compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3229 int num_cycles_2, int num_cycles_1, int round_it,
3230 int add_freqs, struct stru1 *result)
3231{
3232 int g;
3233 int common_time_unit_ps;
3234 int freq1_reduced, freq2_reduced;
3235 int freq_min_reduced;
3236 int freq_max_reduced;
3237 int freq3, freq4;
3238
3239 g = gcd(freq1, freq2);
3240 freq1_reduced = freq1 / g;
3241 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003242 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3243 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003244
3245 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3246 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3247 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3248 if (add_freqs) {
3249 freq3 += freq2_reduced;
3250 freq4 += freq1_reduced;
3251 }
3252
3253 if (round_it) {
3254 result->freq3_to_2_remainder = 0;
3255 result->freq3_to_2_remaindera = 0;
3256 result->freq4_to_max_remainder = 0;
3257 result->divisor_f4_to_f2 = 0;
3258 result->divisor_f3_to_f1 = 0;
3259 } else {
3260 if (freq2_reduced < freq1_reduced) {
3261 result->freq3_to_2_remainder =
3262 result->freq3_to_2_remaindera =
3263 freq3 % freq1_reduced - freq1_reduced + 1;
3264 result->freq4_to_max_remainder =
3265 -(freq4 % freq1_reduced);
3266 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3267 result->divisor_f4_to_f2 =
3268 (freq4 -
3269 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3270 result->freq4_to_2_remainder =
3271 -(char)((freq1_reduced - freq2_reduced) +
3272 ((u8) freq4 -
3273 (freq1_reduced -
3274 freq2_reduced)) % (u8) freq2_reduced);
3275 } else {
3276 if (freq2_reduced > freq1_reduced) {
3277 result->freq4_to_max_remainder =
3278 (freq4 % freq2_reduced) - freq2_reduced + 1;
3279 result->freq4_to_2_remainder =
3280 freq4 % freq_max_reduced -
3281 freq_max_reduced + 1;
3282 } else {
3283 result->freq4_to_max_remainder =
3284 -(freq4 % freq2_reduced);
3285 result->freq4_to_2_remainder =
3286 -(char)(freq4 % freq_max_reduced);
3287 }
3288 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3289 result->divisor_f3_to_f1 =
3290 (freq3 -
3291 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3292 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3293 result->freq3_to_2_remaindera =
3294 -(char)((freq_max_reduced - freq_min_reduced) +
3295 (freq3 -
3296 (freq_max_reduced -
3297 freq_min_reduced)) % freq1_reduced);
3298 }
3299 }
3300 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3301 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3302 if (round_it) {
3303 if (freq2_reduced > freq1_reduced) {
3304 if (freq3 % freq_max_reduced)
3305 result->divisor_f3_to_fmax++;
3306 }
3307 if (freq2_reduced < freq1_reduced) {
3308 if (freq4 % freq_max_reduced)
3309 result->divisor_f4_to_fmax++;
3310 }
3311 }
3312 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3313 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3314 result->freq_min_reduced = freq_min_reduced;
3315 result->common_time_unit_ps = common_time_unit_ps;
3316 result->freq_max_reduced = freq_max_reduced;
3317}
3318
3319static void
3320set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3321 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3322 int num_cycles_4, int reverse)
3323{
3324 struct stru1 vv;
3325 char multiplier;
3326
3327 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3328 0, 1, &vv);
3329
3330 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003331 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003332 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3333 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3334 div_roundup(num_cycles_1,
3335 vv.common_time_unit_ps) +
3336 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3337 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3338
3339 u32 y =
3340 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3341 vv.freq_max_reduced * multiplier)
3342 | (vv.
3343 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3344 multiplier) << 16) | ((u8) (vv.
3345 freq_min_reduced
3346 *
3347 multiplier)
3348 << 24);
3349 u32 x =
3350 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3351 divisor_f3_to_f1
3352 << 16)
3353 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3354 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003355 MCHBAR32(reg) = y;
3356 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003357 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003358 MCHBAR32(reg + 4) = y;
3359 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003360 }
3361}
3362
3363static void
3364set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3365 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3366 int num_cycles_4)
3367{
3368 struct stru1 ratios1;
3369 struct stru1 ratios2;
3370
3371 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3372 0, 1, &ratios2);
3373 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3374 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003375 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003376 ratios1.freq4_to_max_remainder | (ratios2.
3377 freq4_to_max_remainder
3378 << 8)
3379 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3380 divisor_f4_to_fmax
3381 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003382 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3383 (ratios2.freq4_to_max_remainder << 8) |
3384 (ratios1.divisor_f4_to_fmax << 16) |
3385 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003386}
3387
3388static void
3389set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3390 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3391{
3392 struct stru1 ratios;
3393
3394 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3395 round_it, add_freqs, &ratios);
3396 switch (mode) {
3397 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003398 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3399 (ratios.freqs_reversed << 8);
3400 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3401 (ratios.freq4_to_max_remainder << 8) |
3402 (ratios.divisor_f3_to_fmax << 16) |
3403 (ratios.divisor_f4_to_fmax << 20) |
3404 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003405 break;
3406
3407 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003408 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3409 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003410 break;
3411
3412 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003413 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);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003417 break;
3418
3419 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003420 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3421 (ratios.divisor_f4_to_fmax << 8) |
3422 (ratios.freqs_reversed << 12) |
3423 (ratios.freq_min_reduced << 16) |
3424 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003425 break;
3426 }
3427}
3428
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003429static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003430{
3431 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3432 0, 1);
3433 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3434 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3435 1);
3436 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3437 frequency_11(info), 1231, 1524, 0, 1);
3438 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3439 frequency_11(info) / 2, 1278, 2008, 0, 1);
3440 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3441 1167, 1539, 0, 1);
3442 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3443 frequency_11(info) / 2, 1403, 1318, 0, 1);
3444 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3445 1);
3446 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3447 1);
3448 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3449 1, 1);
3450 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3451 1);
3452 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3453 frequency_11(info) / 2, 4000, 0, 0, 0);
3454 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3455 frequency_11(info) / 2, 4000, 4000, 0, 0);
3456
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003457 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003458 printk(RAM_SPEW, "[6dc] <= %x\n",
3459 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003460 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003461 } else
3462 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3463 info->delay46_ps[0], 0,
3464 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003465 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3466 frequency_11(info), 2500, 0, 0, 0);
3467 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3468 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003469 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003470 printk(RAM_SPEW, "[6e8] <= %x\n",
3471 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003472 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003473 } else
3474 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3475 info->delay46_ps[1], 0,
3476 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3478 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3479 470, 0);
3480 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3481 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3482 454, 459, 0);
3483 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3484 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3485 2588, 0);
3486 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3487 2405, 0);
3488 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3489 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3490 480, 0);
3491 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003492 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3493 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003494}
3495
3496static u16 get_max_timing(struct raminfo *info, int channel)
3497{
3498 int slot, rank, lane;
3499 u16 ret = 0;
3500
Felix Held04be2dd2018-07-29 04:53:22 +02003501 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003502 return 384;
3503
3504 if (info->revision < 8)
3505 return 256;
3506
3507 for (slot = 0; slot < NUM_SLOTS; slot++)
3508 for (rank = 0; rank < NUM_RANKS; rank++)
3509 if (info->populated_ranks[channel][slot][rank])
3510 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003511 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003512 get_timing_register_addr
3513 (lane, 0, slot,
3514 rank), 9));
3515 return ret;
3516}
3517
3518static void set_274265(struct raminfo *info)
3519{
3520 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3521 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3522 int delay_e_over_cycle_ps;
3523 int cycletime_ps;
3524 int channel;
3525
3526 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003527 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003528 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3529 cycletime_ps =
3530 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3531 delay_d_ps =
3532 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3533 - info->some_delay_3_ps_rounded + 200;
3534 if (!
3535 ((info->silicon_revision == 0
3536 || info->silicon_revision == 1)
3537 && (info->revision >= 8)))
3538 delay_d_ps += halfcycle_ps(info) * 2;
3539 delay_d_ps +=
3540 halfcycle_ps(info) * (!info->revision_flag_1 +
3541 info->some_delay_2_halfcycles_ceil +
3542 2 * info->some_delay_1_cycle_floor +
3543 info->clock_speed_index +
3544 2 * info->cas_latency - 7 + 11);
3545 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3546
Felix Held04be2dd2018-07-29 04:53:22 +02003547 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3548 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3549 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003550 delay_d_ps += 650;
3551 delay_c_ps = delay_d_ps + 1800;
3552 if (delay_c_ps <= delay_a_ps)
3553 delay_e_ps = 0;
3554 else
3555 delay_e_ps =
3556 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3557 cycletime_ps);
3558
3559 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3560 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3561 delay_f_cycles =
3562 div_roundup(2500 - delay_e_over_cycle_ps,
3563 2 * halfcycle_ps(info));
3564 if (delay_f_cycles > delay_e_cycles) {
3565 info->delay46_ps[channel] = delay_e_ps;
3566 delay_e_cycles = 0;
3567 } else {
3568 info->delay46_ps[channel] =
3569 delay_e_over_cycle_ps +
3570 2 * halfcycle_ps(info) * delay_f_cycles;
3571 delay_e_cycles -= delay_f_cycles;
3572 }
3573
3574 if (info->delay46_ps[channel] < 2500) {
3575 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003576 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003577 }
3578 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3579 if (delay_b_ps <= delay_a_ps)
3580 delay_b_ps = 0;
3581 else
3582 delay_b_ps -= delay_a_ps;
3583 info->delay54_ps[channel] =
3584 cycletime_ps * div_roundup(delay_b_ps,
3585 cycletime_ps) -
3586 2 * halfcycle_ps(info) * delay_e_cycles;
3587 if (info->delay54_ps[channel] < 2500)
3588 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003589 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003590 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3591 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003592 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003593 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003594 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003595 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3596 4 * halfcycle_ps(info)) - 6;
3597 MCHBAR32((channel << 10) + 0x274) =
3598 info->training.reg274265[channel][1] |
3599 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003600 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003601 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3602 4 * halfcycle_ps(info)) + 1;
3603 MCHBAR16((channel << 10) + 0x265) =
3604 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003606 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003607 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608 else
Felix Held04be2dd2018-07-29 04:53:22 +02003609 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610}
3611
3612static void restore_274265(struct raminfo *info)
3613{
3614 int channel;
3615
3616 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003617 MCHBAR32((channel << 10) + 0x274) =
3618 (info->cached_training->reg274265[channel][0] << 16) |
3619 info->cached_training->reg274265[channel][1];
3620 MCHBAR16((channel << 10) + 0x265) =
3621 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003623 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003624 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625 else
Felix Held04be2dd2018-07-29 04:53:22 +02003626 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627}
3628
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629static void dmi_setup(void)
3630{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003631 gav(read8(DEFAULT_DMIBAR + 0x254));
3632 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3633 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003634 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003636 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637
3638 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3639 DEFAULT_GPIOBASE | 0x38);
3640 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3641}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003643void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003646 u16 ggc;
3647 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648
Felix Held04be2dd2018-07-29 04:53:22 +02003649 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3651 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003652 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003653 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654 }
Felix Held29a9c072018-07-29 01:34:45 +02003655#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656 if (!s3resume) {
3657 pre_raminit_3(x2ca8);
3658 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003659 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003660#endif
3661
3662 dmi_setup();
3663
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR16(0x1170) = 0xa880;
3665 MCHBAR8(0x11c1) = 0x1;
3666 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003667 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003669 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3670 /* 0 for 32MB */
3671 gfxsize = 0;
3672 }
3673
3674 ggc = 0xb00 | ((gfxsize + 5) << 4);
3675
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003676 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677
3678 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003679 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680
3681 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003682 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003683 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003684 MCHBAR16_OR(0x2c30, 0x200);
3685 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003686 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003687 pci_read_config8(GMA, 0x62); // = 0x2
3688 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003689 read8(DEFAULT_RCBA + 0x2318);
3690 write8(DEFAULT_RCBA + 0x2318, 0x47);
3691 read8(DEFAULT_RCBA + 0x2320);
3692 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003693 }
3694
Felix Heldf83d80b2018-07-29 05:30:30 +02003695 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003696
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003697 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003698 gav(read32(DEFAULT_RCBA + 0x3428));
3699 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003700}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003701
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003702void raminit(const int s3resume, const u8 *spd_addrmap)
3703{
Martin Roth468d02c2019-10-23 21:44:42 -06003704 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003705 int i;
3706 struct raminfo info;
3707 u8 x2ca8;
3708 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003709 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003710
Felix Held04be2dd2018-07-29 04:53:22 +02003711 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003712
3713 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3714
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003715 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003716
3717 memset(&info, 0x5a, sizeof(info));
3718
3719 info.last_500_command[0] = 0;
3720 info.last_500_command[1] = 0;
3721
3722 info.fsb_frequency = 135 * 2;
3723 info.board_lane_delay[0] = 0x14;
3724 info.board_lane_delay[1] = 0x07;
3725 info.board_lane_delay[2] = 0x07;
3726 info.board_lane_delay[3] = 0x08;
3727 info.board_lane_delay[4] = 0x56;
3728 info.board_lane_delay[5] = 0x04;
3729 info.board_lane_delay[6] = 0x04;
3730 info.board_lane_delay[7] = 0x05;
3731 info.board_lane_delay[8] = 0x10;
3732
3733 info.training.reg_178 = 0;
3734 info.training.reg_10b = 0;
3735
3736 info.heci_bar = 0;
3737 info.memory_reserved_for_heci_mb = 0;
3738
3739 /* before SPD */
3740 timestamp_add_now(101);
3741
Felix Held29a9c072018-07-29 01:34:45 +02003742 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003743 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003744
3745 collect_system_info(&info);
3746
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3748
3749 info.use_ecc = 1;
3750 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003751 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003752 int v;
3753 int try;
3754 int addr;
3755 const u8 useful_addresses[] = {
3756 DEVICE_TYPE,
3757 MODULE_TYPE,
3758 DENSITY,
3759 RANKS_AND_DQ,
3760 MEMORY_BUS_WIDTH,
3761 TIMEBASE_DIVIDEND,
3762 TIMEBASE_DIVISOR,
3763 CYCLETIME,
3764 CAS_LATENCIES_LSB,
3765 CAS_LATENCIES_MSB,
3766 CAS_LATENCY_TIME,
3767 0x11, 0x12, 0x13, 0x14, 0x15,
3768 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3769 0x1c, 0x1d,
3770 THERMAL_AND_REFRESH,
3771 0x20,
3772 REFERENCE_RAW_CARD_USED,
3773 RANK1_ADDRESS_MAPPING,
3774 0x75, 0x76, 0x77, 0x78,
3775 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3776 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3777 0x85, 0x86, 0x87, 0x88,
3778 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3779 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3780 0x95
3781 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003782 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003783 continue;
3784 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003785 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003786 DEVICE_TYPE);
3787 if (v >= 0)
3788 break;
3789 }
3790 if (v < 0)
3791 continue;
3792 for (addr = 0;
3793 addr <
3794 sizeof(useful_addresses) /
3795 sizeof(useful_addresses[0]); addr++)
3796 gav(info.
3797 spd[channel][0][useful_addresses
3798 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003799 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003800 useful_addresses
3801 [addr]));
3802 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3803 die("Only DDR3 is supported");
3804
3805 v = info.spd[channel][0][RANKS_AND_DQ];
3806 info.populated_ranks[channel][0][0] = 1;
3807 info.populated_ranks[channel][0][1] =
3808 ((v >> 3) & 7);
3809 if (((v >> 3) & 7) > 1)
3810 die("At most 2 ranks are supported");
3811 if ((v & 7) == 0 || (v & 7) > 2)
3812 die("Only x8 and x16 modules are supported");
3813 if ((info.
3814 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3815 && (info.
3816 spd[channel][slot][MODULE_TYPE] & 0xF)
3817 != 3)
3818 die("Registered memory is not supported");
3819 info.is_x16_module[channel][0] = (v & 7) - 1;
3820 info.density[channel][slot] =
3821 info.spd[channel][slot][DENSITY] & 0xF;
3822 if (!
3823 (info.
3824 spd[channel][slot][MEMORY_BUS_WIDTH] &
3825 0x18))
3826 info.use_ecc = 0;
3827 }
3828
3829 gav(0x55);
3830
3831 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3832 int v = 0;
3833 for (slot = 0; slot < NUM_SLOTS; slot++)
3834 for (rank = 0; rank < NUM_RANKS; rank++)
3835 v |= info.
3836 populated_ranks[channel][slot][rank]
3837 << (2 * slot + rank);
3838 info.populated_ranks_mask[channel] = v;
3839 }
3840
3841 gav(0x55);
3842
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003843 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003844 }
3845
3846 /* after SPD */
3847 timestamp_add_now(102);
3848
Felix Held04be2dd2018-07-29 04:53:22 +02003849 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850
3851 collect_system_info(&info);
3852 calculate_timings(&info);
3853
Felix Held29a9c072018-07-29 01:34:45 +02003854#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003855 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003856#endif
3857
3858 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003859 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003860 if (x2ca8 == 0 && (reg8 & 0x80)) {
3861 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3862 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3863 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3864 */
3865
3866 /* Clear bit7. */
3867
3868 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3869 (reg8 & ~(1 << 7)));
3870
3871 printk(BIOS_INFO,
3872 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003873 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874 }
3875 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876
3877 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003878 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3879 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880
3881 compute_derived_timings(&info);
3882
3883 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003884 gav(MCHBAR8(0x164));
3885 MCHBAR8(0x164) = 0x26;
3886 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887 }
3888
Felix Held04be2dd2018-07-29 04:53:22 +02003889 MCHBAR32_OR(0x18b4, 0x210000);
3890 MCHBAR32_OR(0x1890, 0x2000000);
3891 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003893 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3894 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895
Felix Held04be2dd2018-07-29 04:53:22 +02003896 gav(MCHBAR16(0x2c10));
3897 MCHBAR16(0x2c10) = 0x412;
3898 gav(MCHBAR16(0x2c10));
3899 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900
Felix Held04be2dd2018-07-29 04:53:22 +02003901 gav(MCHBAR8(0x2ca8)); // !!!!
3902 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003903
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003904 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3905 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003906 gav(MCHBAR32(0x1c04)); // !!!!
3907 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003908
3909 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003910 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911 }
3912
Felix Held04be2dd2018-07-29 04:53:22 +02003913 MCHBAR32(0x18d8) = 0x120000;
3914 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003915 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3916 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003917 MCHBAR32(0x18d8) = 0x40000;
3918 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003919 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3920 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003921 MCHBAR32(0x18d8) = 0x180000;
3922 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003923 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3924 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003925 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003926
Felix Held04be2dd2018-07-29 04:53:22 +02003927 gav(MCHBAR32(0x18dc)); // !!!!
3928 MCHBAR32(0x18dc) = 0x3;
3929 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930
3931 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003932 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003933 }
3934
Felix Held04be2dd2018-07-29 04:53:22 +02003935 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003936 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR32(0x1a10) = 0x4200010e;
3938 MCHBAR32_OR(0x18b8, 0x200);
3939 gav(MCHBAR32(0x1918)); // !!!!
3940 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003941
Felix Held04be2dd2018-07-29 04:53:22 +02003942 gav(MCHBAR32(0x18b8)); // !!!!
3943 MCHBAR32(0x18b8) = 0xe00;
3944 gav(MCHBAR32(0x182c)); // !!!!
3945 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003946 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3947 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003948 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3949 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR32_AND(0x18b4, 0xffff7fff);
3952 gav(MCHBAR32(0x1a68)); // !!!!
3953 MCHBAR32(0x1a68) = 0x343800;
3954 gav(MCHBAR32(0x1e68)); // !!!!
3955 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003956
3957 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003958 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003959 }
3960
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003961 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3962 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3963 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3964 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3965 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3966 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3967 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003968 gav(MCHBAR32(0x1af0)); // !!!!
3969 gav(MCHBAR32(0x1af0)); // !!!!
3970 MCHBAR32(0x1af0) = 0x1f020003;
3971 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003972
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003973 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003974 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975 }
3976
Felix Held04be2dd2018-07-29 04:53:22 +02003977 gav(MCHBAR32(0x1890)); // !!!!
3978 MCHBAR32(0x1890) = 0x80102;
3979 gav(MCHBAR32(0x18b4)); // !!!!
3980 MCHBAR32(0x18b4) = 0x216000;
3981 MCHBAR32(0x18a4) = 0x22222222;
3982 MCHBAR32(0x18a8) = 0x22222222;
3983 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984
3985 udelay(1000);
3986
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003987 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003988
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003989 if (x2ca8 == 0) {
3990 int j;
3991 if (s3resume && info.cached_training) {
3992 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003993 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003994 info.cached_training->reg2ca9_bit0);
3995 for (i = 0; i < 2; i++)
3996 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003997 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003998 i, j, info.cached_training->reg274265[i][j]);
3999 } else {
4000 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004001 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004002 info.training.reg2ca9_bit0);
4003 for (i = 0; i < 2; i++)
4004 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004005 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004006 i, j, info.training.reg274265[i][j]);
4007 }
4008
4009 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004010
4011 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004012 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004013 }
4014
4015 udelay(1000);
4016
4017 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004018 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004019 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004020 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4021 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4022 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004023
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004024 MCHBAR8(0x1150);
4025 MCHBAR8(0x1151);
4026 MCHBAR8(0x1022);
4027 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004028 MCHBAR32(0x1300) = 0x60606060;
4029 MCHBAR32(0x1304) = 0x60606060;
4030 MCHBAR32(0x1308) = 0x78797a7b;
4031 MCHBAR32(0x130c) = 0x7c7d7e7f;
4032 MCHBAR32(0x1310) = 0x60606060;
4033 MCHBAR32(0x1314) = 0x60606060;
4034 MCHBAR32(0x1318) = 0x60606060;
4035 MCHBAR32(0x131c) = 0x60606060;
4036 MCHBAR32(0x1320) = 0x50515253;
4037 MCHBAR32(0x1324) = 0x54555657;
4038 MCHBAR32(0x1328) = 0x58595a5b;
4039 MCHBAR32(0x132c) = 0x5c5d5e5f;
4040 MCHBAR32(0x1330) = 0x40414243;
4041 MCHBAR32(0x1334) = 0x44454647;
4042 MCHBAR32(0x1338) = 0x48494a4b;
4043 MCHBAR32(0x133c) = 0x4c4d4e4f;
4044 MCHBAR32(0x1340) = 0x30313233;
4045 MCHBAR32(0x1344) = 0x34353637;
4046 MCHBAR32(0x1348) = 0x38393a3b;
4047 MCHBAR32(0x134c) = 0x3c3d3e3f;
4048 MCHBAR32(0x1350) = 0x20212223;
4049 MCHBAR32(0x1354) = 0x24252627;
4050 MCHBAR32(0x1358) = 0x28292a2b;
4051 MCHBAR32(0x135c) = 0x2c2d2e2f;
4052 MCHBAR32(0x1360) = 0x10111213;
4053 MCHBAR32(0x1364) = 0x14151617;
4054 MCHBAR32(0x1368) = 0x18191a1b;
4055 MCHBAR32(0x136c) = 0x1c1d1e1f;
4056 MCHBAR32(0x1370) = 0x10203;
4057 MCHBAR32(0x1374) = 0x4050607;
4058 MCHBAR32(0x1378) = 0x8090a0b;
4059 MCHBAR32(0x137c) = 0xc0d0e0f;
4060 MCHBAR8(0x11cc) = 0x4e;
4061 MCHBAR32(0x1110) = 0x73970404;
4062 MCHBAR32(0x1114) = 0x72960404;
4063 MCHBAR32(0x1118) = 0x6f950404;
4064 MCHBAR32(0x111c) = 0x6d940404;
4065 MCHBAR32(0x1120) = 0x6a930404;
4066 MCHBAR32(0x1124) = 0x68a41404;
4067 MCHBAR32(0x1128) = 0x66a21404;
4068 MCHBAR32(0x112c) = 0x63a01404;
4069 MCHBAR32(0x1130) = 0x609e1404;
4070 MCHBAR32(0x1134) = 0x5f9c1404;
4071 MCHBAR32(0x1138) = 0x5c961404;
4072 MCHBAR32(0x113c) = 0x58a02404;
4073 MCHBAR32(0x1140) = 0x54942404;
4074 MCHBAR32(0x1190) = 0x900080a;
4075 MCHBAR16(0x11c0) = 0xc40b;
4076 MCHBAR16(0x11c2) = 0x303;
4077 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004078 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004079 MCHBAR32(0x11b8) = 0x70c3000;
4080 MCHBAR8(0x11ec) = 0xa;
4081 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004082 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004083 MCHBAR16(0x11ca) = 0xfa;
4084 MCHBAR32(0x11e4) = 0x4e20;
4085 MCHBAR8(0x11bc) = 0xf;
4086 MCHBAR16(0x11da) = 0x19;
4087 MCHBAR16(0x11ba) = 0x470c;
4088 MCHBAR32(0x1680) = 0xe6ffe4ff;
4089 MCHBAR32(0x1684) = 0xdeffdaff;
4090 MCHBAR32(0x1688) = 0xd4ffd0ff;
4091 MCHBAR32(0x168c) = 0xccffc6ff;
4092 MCHBAR32(0x1690) = 0xc0ffbeff;
4093 MCHBAR32(0x1694) = 0xb8ffb0ff;
4094 MCHBAR32(0x1698) = 0xa8ff0000;
4095 MCHBAR32(0x169c) = 0xc00;
4096 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004097 }
4098
Felix Held04be2dd2018-07-29 04:53:22 +02004099 MCHBAR32(0x124c) = 0x15040d00;
4100 MCHBAR32(0x1250) = 0x7f0000;
4101 MCHBAR32(0x1254) = 0x1e220004;
4102 MCHBAR32(0x1258) = 0x4000004;
4103 MCHBAR32(0x1278) = 0x0;
4104 MCHBAR32(0x125c) = 0x0;
4105 MCHBAR32(0x1260) = 0x0;
4106 MCHBAR32(0x1264) = 0x0;
4107 MCHBAR32(0x1268) = 0x0;
4108 MCHBAR32(0x126c) = 0x0;
4109 MCHBAR32(0x1270) = 0x0;
4110 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004111 }
4112
4113 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004114 MCHBAR16(0x1214) = 0x320;
4115 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004116 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4117 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004118 MCHBAR32(0x1400) = 0x13040020;
4119 MCHBAR32(0x1404) = 0xe090120;
4120 MCHBAR32(0x1408) = 0x5120220;
4121 MCHBAR32(0x140c) = 0x5120330;
4122 MCHBAR32(0x1410) = 0xe090220;
4123 MCHBAR32(0x1414) = 0x1010001;
4124 MCHBAR32(0x1418) = 0x1110000;
4125 MCHBAR32(0x141c) = 0x9020020;
4126 MCHBAR32(0x1420) = 0xd090220;
4127 MCHBAR32(0x1424) = 0x2090220;
4128 MCHBAR32(0x1428) = 0x2090330;
4129 MCHBAR32(0x142c) = 0xd090220;
4130 MCHBAR32(0x1430) = 0x1010001;
4131 MCHBAR32(0x1434) = 0x1110000;
4132 MCHBAR32(0x1438) = 0x11040020;
4133 MCHBAR32(0x143c) = 0x4030220;
4134 MCHBAR32(0x1440) = 0x1060220;
4135 MCHBAR32(0x1444) = 0x1060330;
4136 MCHBAR32(0x1448) = 0x4030220;
4137 MCHBAR32(0x144c) = 0x1010001;
4138 MCHBAR32(0x1450) = 0x1110000;
4139 MCHBAR32(0x1454) = 0x4010020;
4140 MCHBAR32(0x1458) = 0xb090220;
4141 MCHBAR32(0x145c) = 0x1090220;
4142 MCHBAR32(0x1460) = 0x1090330;
4143 MCHBAR32(0x1464) = 0xb090220;
4144 MCHBAR32(0x1468) = 0x1010001;
4145 MCHBAR32(0x146c) = 0x1110000;
4146 MCHBAR32(0x1470) = 0xf040020;
4147 MCHBAR32(0x1474) = 0xa090220;
4148 MCHBAR32(0x1478) = 0x1120220;
4149 MCHBAR32(0x147c) = 0x1120330;
4150 MCHBAR32(0x1480) = 0xa090220;
4151 MCHBAR32(0x1484) = 0x1010001;
4152 MCHBAR32(0x1488) = 0x1110000;
4153 MCHBAR32(0x148c) = 0x7020020;
4154 MCHBAR32(0x1490) = 0x1010220;
4155 MCHBAR32(0x1494) = 0x10210;
4156 MCHBAR32(0x1498) = 0x10320;
4157 MCHBAR32(0x149c) = 0x1010220;
4158 MCHBAR32(0x14a0) = 0x1010001;
4159 MCHBAR32(0x14a4) = 0x1110000;
4160 MCHBAR32(0x14a8) = 0xd040020;
4161 MCHBAR32(0x14ac) = 0x8090220;
4162 MCHBAR32(0x14b0) = 0x1111310;
4163 MCHBAR32(0x14b4) = 0x1111420;
4164 MCHBAR32(0x14b8) = 0x8090220;
4165 MCHBAR32(0x14bc) = 0x1010001;
4166 MCHBAR32(0x14c0) = 0x1110000;
4167 MCHBAR32(0x14c4) = 0x3010020;
4168 MCHBAR32(0x14c8) = 0x7090220;
4169 MCHBAR32(0x14cc) = 0x1081310;
4170 MCHBAR32(0x14d0) = 0x1081420;
4171 MCHBAR32(0x14d4) = 0x7090220;
4172 MCHBAR32(0x14d8) = 0x1010001;
4173 MCHBAR32(0x14dc) = 0x1110000;
4174 MCHBAR32(0x14e0) = 0xb040020;
4175 MCHBAR32(0x14e4) = 0x2030220;
4176 MCHBAR32(0x14e8) = 0x1051310;
4177 MCHBAR32(0x14ec) = 0x1051420;
4178 MCHBAR32(0x14f0) = 0x2030220;
4179 MCHBAR32(0x14f4) = 0x1010001;
4180 MCHBAR32(0x14f8) = 0x1110000;
4181 MCHBAR32(0x14fc) = 0x5020020;
4182 MCHBAR32(0x1500) = 0x5090220;
4183 MCHBAR32(0x1504) = 0x2071310;
4184 MCHBAR32(0x1508) = 0x2071420;
4185 MCHBAR32(0x150c) = 0x5090220;
4186 MCHBAR32(0x1510) = 0x1010001;
4187 MCHBAR32(0x1514) = 0x1110000;
4188 MCHBAR32(0x1518) = 0x7040120;
4189 MCHBAR32(0x151c) = 0x2090220;
4190 MCHBAR32(0x1520) = 0x70b1210;
4191 MCHBAR32(0x1524) = 0x70b1310;
4192 MCHBAR32(0x1528) = 0x2090220;
4193 MCHBAR32(0x152c) = 0x1010001;
4194 MCHBAR32(0x1530) = 0x1110000;
4195 MCHBAR32(0x1534) = 0x1010110;
4196 MCHBAR32(0x1538) = 0x1081310;
4197 MCHBAR32(0x153c) = 0x5041200;
4198 MCHBAR32(0x1540) = 0x5041310;
4199 MCHBAR32(0x1544) = 0x1081310;
4200 MCHBAR32(0x1548) = 0x1010001;
4201 MCHBAR32(0x154c) = 0x1110000;
4202 MCHBAR32(0x1550) = 0x1040120;
4203 MCHBAR32(0x1554) = 0x4051210;
4204 MCHBAR32(0x1558) = 0xd051200;
4205 MCHBAR32(0x155c) = 0xd051200;
4206 MCHBAR32(0x1560) = 0x4051210;
4207 MCHBAR32(0x1564) = 0x1010001;
4208 MCHBAR32(0x1568) = 0x1110000;
4209 MCHBAR16(0x1222) = 0x220a;
4210 MCHBAR16(0x123c) = 0x1fc0;
4211 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004212 }
4213
Felix Heldf83d80b2018-07-29 05:30:30 +02004214 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004215 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004216 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004217
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004218 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004219
4220 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004221 MCHBAR8_AND(0x2ca8, ~3);
4222 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004223 /* This issues a CPU reset without resetting the platform */
4224 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004225 /* Write back the S3 state to PM1_CNT to let the reset CPU
4226 know it also needs to take the s3 path. */
4227 if (s3resume)
4228 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4229 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004230 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004231 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004232 }
4233
Felix Held04be2dd2018-07-29 04:53:22 +02004234 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004235 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004236 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004237 MCHBAR16(0x2c20); // !!!!
4238 MCHBAR16(0x2c10); // !!!!
4239 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004240 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004241 udelay(1000);
4242 write_1d0(0, 0x33d, 0, 0);
4243 write_500(&info, 0, 0, 0xb61, 0, 0);
4244 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004245 MCHBAR32(0x1a30) = 0x0;
4246 MCHBAR32(0x1a34) = 0x0;
4247 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4248 (info.populated_ranks[0][0][0] * 0xa0);
4249 MCHBAR16(0x616) = 0x26a;
4250 MCHBAR32(0x134) = 0x856000;
4251 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004252 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4253 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004255 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4256 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004257 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004259 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4260 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004261 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4262 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4263 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4264 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4265 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4266 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4267 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4268 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4269 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4270 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004271 }
4272
4273 write_1d0(0x4, 0x151, 4, 1);
4274 write_1d0(0, 0x142, 3, 1);
4275 rdmsr(0x1ac); // !!!!
4276 write_500(&info, 1, 1, 0x6b3, 4, 1);
4277 write_500(&info, 1, 1, 0x6cf, 4, 1);
4278
4279 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4280
4281 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4282 populated_ranks[0]
4283 [0][0]) << 0),
4284 0x1d1, 3, 1);
4285 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004286 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4287 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004288 }
4289
4290 set_334(0);
4291
4292 program_base_timings(&info);
4293
Felix Held04be2dd2018-07-29 04:53:22 +02004294 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004295
4296 write_1d0(0x2, 0x1d5, 2, 1);
4297 write_1d0(0x20, 0x166, 7, 1);
4298 write_1d0(0x0, 0xeb, 3, 1);
4299 write_1d0(0x0, 0xf3, 6, 1);
4300
4301 for (channel = 0; channel < NUM_CHANNELS; channel++)
4302 for (lane = 0; lane < 9; lane++) {
4303 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4304 u8 a;
4305 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4306 write_500(&info, channel, a, addr, 6, 1);
4307 }
4308
4309 udelay(1000);
4310
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004311 if (s3resume) {
4312 if (info.cached_training == NULL) {
4313 u32 reg32;
4314 printk(BIOS_ERR,
4315 "Couldn't find training data. Rebooting\n");
4316 reg32 = inl(DEFAULT_PMBASE + 0x04);
4317 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004318 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004319 }
4320 int tm;
4321 info.training = *info.cached_training;
4322 for (tm = 0; tm < 4; tm++)
4323 for (channel = 0; channel < NUM_CHANNELS; channel++)
4324 for (slot = 0; slot < NUM_SLOTS; slot++)
4325 for (rank = 0; rank < NUM_RANKS; rank++)
4326 for (lane = 0; lane < 9; lane++)
4327 write_500(&info,
4328 channel,
4329 info.training.
4330 lane_timings
4331 [tm][channel]
4332 [slot][rank]
4333 [lane],
4334 get_timing_register_addr
4335 (lane, tm,
4336 slot, rank),
4337 9, 0);
4338 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4339 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4340 }
4341
Felix Heldf83d80b2018-07-29 05:30:30 +02004342 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004343 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004344 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004345 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004346
4347 program_board_delay(&info);
4348
Felix Held04be2dd2018-07-29 04:53:22 +02004349 MCHBAR8(0x5ff) = 0x0;
4350 MCHBAR8(0x5ff) = 0x80;
4351 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004352
Felix Held04be2dd2018-07-29 04:53:22 +02004353 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004354 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004355 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004356 gav(read_1d0(0x14b, 7)); // = 0x81023100
4357 write_1d0(0x30, 0x14b, 7, 1);
4358 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4359 write_1d0(7, 0xd6, 6, 1);
4360 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4361 write_1d0(7, 0x328, 6, 1);
4362
4363 for (channel = 0; channel < NUM_CHANNELS; channel++)
4364 set_4cf(&info, channel,
4365 info.populated_ranks[channel][0][0] ? 8 : 0);
4366
4367 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4368 write_1d0(2, 0x116, 4, 1);
4369 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4370 write_1d0(0, 0xae, 6, 1);
4371 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4372 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004373 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4374 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004375 MCHBAR32_AND(0x140, ~0x07000000);
4376 MCHBAR32_AND(0x138, ~0x07000000);
4377 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004378 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004379 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004380 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004381
4382 {
4383 u32 t;
4384 u8 val_a1;
4385 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4386 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4387 rmw_1d0(0x320, 0x07,
4388 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4389 rmw_1d0(0x14b, 0x78,
4390 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4391 4), 7,
4392 1);
4393 rmw_1d0(0xce, 0x38,
4394 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4395 4), 6,
4396 1);
4397 }
4398
4399 for (channel = 0; channel < NUM_CHANNELS; channel++)
4400 set_4cf(&info, channel,
4401 info.populated_ranks[channel][0][0] ? 9 : 1);
4402
4403 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004404 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004405 write_1d0(2, 0xae, 6, 1);
4406 write_1d0(2, 0x300, 6, 1);
4407 write_1d0(2, 0x121, 3, 1);
4408 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4409 write_1d0(4, 0xd6, 6, 1);
4410 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4411 write_1d0(4, 0x328, 6, 1);
4412
4413 for (channel = 0; channel < NUM_CHANNELS; channel++)
4414 set_4cf(&info, channel,
4415 info.populated_ranks[channel][0][0] ? 9 : 0);
4416
Felix Held04be2dd2018-07-29 04:53:22 +02004417 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4418 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004419 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004420 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004421 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4422 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4423 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4424 write_1d0(0, 0x21c, 6, 1);
4425 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4426 write_1d0(0x35, 0x14b, 7, 1);
4427
4428 for (channel = 0; channel < NUM_CHANNELS; channel++)
4429 set_4cf(&info, channel,
4430 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4431
4432 set_334(1);
4433
Felix Held04be2dd2018-07-29 04:53:22 +02004434 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004435
4436 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4437 write_500(&info, channel,
4438 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4439 1);
4440 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4441 }
Felix Held04be2dd2018-07-29 04:53:22 +02004442 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4443 MCHBAR16(0x6c0) = 0x14a0;
4444 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4445 MCHBAR16(0x232) = 0x8;
4446 /* 0x40004 or 0 depending on ? */
4447 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4448 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4449 MCHBAR32(0x128) = 0x2150d05;
4450 MCHBAR8(0x12c) = 0x1f;
4451 MCHBAR8(0x12d) = 0x56;
4452 MCHBAR8(0x12e) = 0x31;
4453 MCHBAR8(0x12f) = 0x0;
4454 MCHBAR8(0x271) = 0x2;
4455 MCHBAR8(0x671) = 0x2;
4456 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004458 MCHBAR32(0x294 + (channel << 10)) =
4459 (info.populated_ranks_mask[channel] & 3) << 16;
4460 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4461 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004462 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004463 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4464 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004465
4466 if (!s3resume)
4467 jedec_init(&info);
4468
4469 int totalrank = 0;
4470 for (channel = 0; channel < NUM_CHANNELS; channel++)
4471 for (slot = 0; slot < NUM_SLOTS; slot++)
4472 for (rank = 0; rank < NUM_RANKS; rank++)
4473 if (info.populated_ranks[channel][slot][rank]) {
4474 jedec_read(&info, channel, slot, rank,
4475 totalrank, 0xa, 0x400);
4476 totalrank++;
4477 }
4478
Felix Held04be2dd2018-07-29 04:53:22 +02004479 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004480
Felix Heldf83d80b2018-07-29 05:30:30 +02004481 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4482 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004483
4484 if (!s3resume) {
4485 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004486 MCHBAR32(0x294 + (channel << 10)) =
4487 (info.populated_ranks_mask[channel] & 3) << 16;
4488 MCHBAR16(0x298 + (channel << 10)) =
4489 info.populated_ranks[channel][0][0] |
4490 (info.populated_ranks[channel][0][1] << 5);
4491 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004493 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004494
4495 {
4496 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004497 a = MCHBAR8(0x243);
4498 b = MCHBAR8(0x643);
4499 MCHBAR8(0x243) = a | 2;
4500 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004501 }
4502
4503 write_1d0(7, 0x19b, 3, 1);
4504 write_1d0(7, 0x1c0, 3, 1);
4505 write_1d0(4, 0x1c6, 4, 1);
4506 write_1d0(4, 0x1cc, 4, 1);
4507 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4508 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004509 MCHBAR32(0x584) = 0xfffff;
4510 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511
4512 for (channel = 0; channel < NUM_CHANNELS; channel++)
4513 for (slot = 0; slot < NUM_SLOTS; slot++)
4514 for (rank = 0; rank < NUM_RANKS; rank++)
4515 if (info.
4516 populated_ranks[channel][slot]
4517 [rank])
4518 config_rank(&info, s3resume,
4519 channel, slot,
4520 rank);
4521
Felix Held04be2dd2018-07-29 04:53:22 +02004522 MCHBAR8(0x243) = 0x1;
4523 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524 }
4525
4526 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004527 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004528 write_26c(0, 0x820);
4529 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004530 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 /* end */
4532
4533 if (s3resume) {
4534 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004535 MCHBAR32(0x294 + (channel << 10)) =
4536 (info.populated_ranks_mask[channel] & 3) << 16;
4537 MCHBAR16(0x298 + (channel << 10)) =
4538 info.populated_ranks[channel][0][0] |
4539 (info.populated_ranks[channel][0][1] << 5);
4540 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004542 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 }
4544
Felix Held04be2dd2018-07-29 04:53:22 +02004545 MCHBAR32_AND(0xfa4, ~0x01000002);
4546 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004548 /* Before training. */
4549 timestamp_add_now(103);
4550
4551 if (!s3resume)
4552 ram_training(&info);
4553
4554 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004555 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556
4557 dump_timings(&info);
4558
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 program_modules_memory_map(&info, 0);
4560 program_total_memory_map(&info);
4561
4562 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004564 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004565 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004567 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568 else
Felix Held04be2dd2018-07-29 04:53:22 +02004569 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR32_AND(0xfac, ~0x80000000);
4572 MCHBAR32(0xfb4) = 0x4800;
4573 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4574 MCHBAR32(0xe94) = 0x7ffff;
4575 MCHBAR32(0xfc0) = 0x80002040;
4576 MCHBAR32(0xfc4) = 0x701246;
4577 MCHBAR8_AND(0xfc8, ~0x70);
4578 MCHBAR32_OR(0xe5c, 0x1000000);
4579 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4580 MCHBAR32(0x50) = 0x700b0;
4581 MCHBAR32(0x3c) = 0x10;
4582 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4583 MCHBAR8_OR(0xff4, 0x2);
4584 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
Felix Held29a9c072018-07-29 01:34:45 +02004586#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4588 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4589 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004590
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004591 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4592 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4593 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594
4595#else
4596 {
4597 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004598 // = 0xe911714b
4599 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4600 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4601 // = 0xe911714b
4602 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4603 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604 }
4605#endif
4606
4607 {
4608 u32 eax;
4609
4610 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004611 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4612 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4613 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004614 }
4615
4616 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004617 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004618 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004619 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004620 else
Felix Held04be2dd2018-07-29 04:53:22 +02004621 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004622
Felix Held04be2dd2018-07-29 04:53:22 +02004623 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624
Felix Held04be2dd2018-07-29 04:53:22 +02004625 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004627 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004628 else
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630 }
4631
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633
4634 {
4635 u8 al;
4636 al = 0xd;
4637 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4638 al += 2;
4639 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641 }
4642
4643 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4645 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4646 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4647 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 }
4649 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004650 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004651 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004652 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004653 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004654 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004655 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR8_OR(0x1210, 2);
4657 MCHBAR32(0x1200) = 0x8800440;
4658 MCHBAR32(0x1204) = 0x53ff0453;
4659 MCHBAR32(0x1208) = 0x19002043;
4660 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
4662 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004663 MCHBAR16(0x1214) = 0x220;
4664 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004665 }
4666
Felix Held04be2dd2018-07-29 04:53:22 +02004667 MCHBAR8_OR(0x1214, 0x4);
4668 MCHBAR8(0x120c) = 0x1;
4669 MCHBAR8(0x1218) = 0x3;
4670 MCHBAR8(0x121a) = 0x3;
4671 MCHBAR8(0x121c) = 0x3;
4672 MCHBAR16(0xc14) = 0x0;
4673 MCHBAR16(0xc20) = 0x0;
4674 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675
4676 /* revision dependent here. */
4677
Felix Held04be2dd2018-07-29 04:53:22 +02004678 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004679
4680 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682
Felix Held04be2dd2018-07-29 04:53:22 +02004683 MCHBAR16_OR(0x1230, 0x8000);
4684 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004685
4686 u8 bl, ebpb;
4687 u16 reg_1020;
4688
Felix Held04be2dd2018-07-29 04:53:22 +02004689 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4690 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR32(0x1000) = 0x100;
4693 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
4695 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697 bl = reg_1020 >> 8;
4698 ebpb = reg_1020 & 0xff;
4699 } else {
4700 ebpb = 0;
4701 bl = 8;
4702 }
4703
4704 rdmsr(0x1a2);
4705
Felix Held04be2dd2018-07-29 04:53:22 +02004706 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709
Felix Held04be2dd2018-07-29 04:53:22 +02004710 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711
Felix Held04be2dd2018-07-29 04:53:22 +02004712 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004714 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4715 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004716 }
4717
4718 setup_heci_uma(&info);
4719
4720 if (info.uma_enabled) {
4721 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR32_OR(0x11b0, 0x4000);
4723 MCHBAR32_OR(0x11b4, 0x4000);
4724 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725
Felix Held04be2dd2018-07-29 04:53:22 +02004726 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4727 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4728 MCHBAR16_OR(0x1170, 0x1000);
4729
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004730 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004731
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004732 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004733 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004734 ;
4735 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004736 }
4737
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004738 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4739 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004740 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004741 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 udelay(1000);
4744 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004745 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4746
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004747 if (!s3resume)
4748 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004749 if (s3resume && cbmem_wasnot_inited) {
4750 u32 reg32;
4751 printk(BIOS_ERR, "Failed S3 resume.\n");
4752 ram_check(0x100000, 0x200000);
4753
4754 /* Clear SLP_TYPE. */
4755 reg32 = inl(DEFAULT_PMBASE + 0x04);
4756 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4757
4758 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004759 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004760 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761}