blob: 38a879c52a59dbf4be1504e3c776ed692534584d [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.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
Angel Pons36592bf2020-09-14 18:52:44 +020064#define MRC_CACHE_VERSION 3
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
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
Martin Roth468d02c2019-10-23 21:44:42 -0600195 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196
197 struct ram_training training;
198 u32 last_500_command[2];
199
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100200 u32 delay46_ps[2];
201 u32 delay54_ps[2];
202 u8 revision_flag_1;
203 u8 some_delay_1_cycle_floor;
204 u8 some_delay_2_halfcycles_ceil;
205 u8 some_delay_3_ps_rounded;
206
207 const struct ram_training *cached_training;
208};
209
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200210/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100211timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200212
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100213static void
214write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
215 int flag);
216
217/* OK */
218static u16
219read_500(struct raminfo *info, int channel, u16 addr, int split)
220{
221 u32 val;
222 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200223 MCHBAR32(0x500 + (channel << 10)) = 0;
224 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
225 ;
226 MCHBAR32(0x500 + (channel << 10)) =
227 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
228 + 0xb88 - addr);
229 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
230 ;
231 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232 return val & ((1 << split) - 1);
233}
234
235/* OK */
236static void
237write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
238 int flag)
239{
240 if (info->last_500_command[channel] == 0x80000000) {
241 info->last_500_command[channel] = 0x40000000;
242 write_500(info, channel, 0, 0xb61, 0, 0);
243 }
Felix Held04be2dd2018-07-29 04:53:22 +0200244 MCHBAR32(0x500 + (channel << 10)) = 0;
245 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
246 ;
247 MCHBAR32(0x504 + (channel << 10)) =
248 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
249 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200250 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200251 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100252}
253
254static int rw_test(int rank)
255{
256 const u32 mask = 0xf00fc33c;
257 int ok = 0xff;
258 int i;
259 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800260 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261 sfence();
262 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800263 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100264 sfence();
265 for (i = 0; i < 32; i++) {
266 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800267 write32p((rank << 28) | (i << 3), pat);
268 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100269 }
270 sfence();
271 for (i = 0; i < 32; i++) {
272 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
273 int j;
274 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800275 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276 for (j = 0; j < 4; j++)
277 if (((val >> (j * 8)) & 0xff) != pat)
278 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 for (j = 0; j < 4; j++)
281 if (((val >> (j * 8)) & 0xff) != pat)
282 ok &= ~(16 << j);
283 }
284 sfence();
285 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800286 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100287 sfence();
288 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800289 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100290
291 return ok;
292}
293
294static void
295program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
296{
297 int lane;
298 for (lane = 0; lane < 8; lane++) {
299 write_500(info, channel,
300 base +
301 info->training.
302 lane_timings[2][channel][slot][rank][lane],
303 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
304 write_500(info, channel,
305 base +
306 info->training.
307 lane_timings[3][channel][slot][rank][lane],
308 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
309 }
310}
311
312static void write_26c(int channel, u16 si)
313{
Felix Held04be2dd2018-07-29 04:53:22 +0200314 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
315 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
316 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100317}
318
319static u32 get_580(int channel, u8 addr)
320{
321 u32 ret;
322 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200323 MCHBAR8(0x5ff) = 0x0;
324 MCHBAR8(0x5ff) = 0x80;
325 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
326 MCHBAR8_OR(0x580 + (channel << 10), 1);
327 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
328 ;
329 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100330 return ret;
331}
332
333const int cached_config = 0;
334
335#define NUM_CHANNELS 2
336#define NUM_SLOTS 2
337#define NUM_RANKS 2
338#define RANK_SHIFT 28
339#define CHANNEL_SHIFT 10
340
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100341static void seq9(struct raminfo *info, int channel, int slot, int rank)
342{
343 int i, lane;
344
345 for (i = 0; i < 2; i++)
346 for (lane = 0; lane < 8; lane++)
347 write_500(info, channel,
348 info->training.lane_timings[i +
349 1][channel][slot]
350 [rank][lane], get_timing_register_addr(lane,
351 i + 1,
352 slot,
353 rank),
354 9, 0);
355
356 write_1d0(1, 0x103, 6, 1);
357 for (lane = 0; lane < 8; lane++)
358 write_500(info, channel,
359 info->training.
360 lane_timings[0][channel][slot][rank][lane],
361 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
362
363 for (i = 0; i < 2; i++) {
364 for (lane = 0; lane < 8; lane++)
365 write_500(info, channel,
366 info->training.lane_timings[i +
367 1][channel][slot]
368 [rank][lane], get_timing_register_addr(lane,
369 i + 1,
370 slot,
371 rank),
372 9, 0);
373 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
374 }
375
376 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200377 MCHBAR8(0x5ff) = 0x0;
378 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100379 write_1d0(0x2, 0x142, 3, 1);
380 for (lane = 0; lane < 8; lane++) {
381 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
382 info->training.lane_timings[2][channel][slot][rank][lane] =
383 read_500(info, channel,
384 get_timing_register_addr(lane, 2, slot, rank), 9);
385 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
386 info->training.lane_timings[3][channel][slot][rank][lane] =
387 info->training.lane_timings[2][channel][slot][rank][lane] +
388 0x20;
389 }
390}
391
392static int count_ranks_in_channel(struct raminfo *info, int channel)
393{
394 int slot, rank;
395 int res = 0;
396 for (slot = 0; slot < NUM_SLOTS; slot++)
397 for (rank = 0; rank < NUM_SLOTS; rank++)
398 res += info->populated_ranks[channel][slot][rank];
399 return res;
400}
401
402static void
403config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
404{
405 int add;
406
407 write_1d0(0, 0x178, 7, 1);
408 seq9(info, channel, slot, rank);
409 program_timings(info, 0x80, channel, slot, rank);
410
411 if (channel == 0)
412 add = count_ranks_in_channel(info, 1);
413 else
414 add = 0;
415 if (!s3resume)
416 gav(rw_test(rank + add));
417 program_timings(info, 0x00, channel, slot, rank);
418 if (!s3resume)
419 gav(rw_test(rank + add));
420 if (!s3resume)
421 gav(rw_test(rank + add));
422 write_1d0(0, 0x142, 3, 1);
423 write_1d0(0, 0x103, 6, 1);
424
425 gav(get_580(channel, 0xc | (rank << 5)));
426 gav(read_1d0(0x142, 3));
427
Felix Held04be2dd2018-07-29 04:53:22 +0200428 MCHBAR8(0x5ff) = 0x0;
429 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100430}
431
432static void set_4cf(struct raminfo *info, int channel, u8 val)
433{
434 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
435 write_500(info, channel, val, 0x4cf, 4, 1);
436 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
437 write_500(info, channel, val, 0x659, 4, 1);
438 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
439 write_500(info, channel, val, 0x697, 4, 1);
440}
441
442static void set_334(int zero)
443{
444 int j, k, channel;
445 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
446 u32 vd8[2][16];
447
448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
449 for (j = 0; j < 4; j++) {
450 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
451 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
452 u16 c;
453 if ((j == 0 || j == 3) && zero)
454 c = 0;
455 else if (j == 3)
456 c = 0x5f;
457 else
458 c = 0x5f5f;
459
460 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200461 MCHBAR32(0x138 + 8 * k) =
462 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100463 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200464 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100465 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200466 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100467 }
468
Felix Held22ca8cb2018-07-29 05:09:44 +0200469 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
470 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200471 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
472 zero ? 0 : (0x18191819 & lmask);
473 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
474 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
475 zero ? 0 : (a & lmask);
476 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100478 }
479 }
480
Felix Held04be2dd2018-07-29 04:53:22 +0200481 MCHBAR32_OR(0x130, 1);
482 while (MCHBAR8(0x130) & 1)
483 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484}
485
486static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
487{
488 u32 v;
489 v = read_1d0(addr, split);
490 write_1d0((v & and) | or, addr, split, flag);
491}
492
493static int find_highest_bit_set(u16 val)
494{
495 int i;
496 for (i = 15; i >= 0; i--)
497 if (val & (1 << i))
498 return i;
499 return -1;
500}
501
502static int find_lowest_bit_set32(u32 val)
503{
504 int i;
505 for (i = 0; i < 32; i++)
506 if (val & (1 << i))
507 return i;
508 return -1;
509}
510
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100511enum {
512 DEVICE_TYPE = 2,
513 MODULE_TYPE = 3,
514 DENSITY = 4,
515 RANKS_AND_DQ = 7,
516 MEMORY_BUS_WIDTH = 8,
517 TIMEBASE_DIVIDEND = 10,
518 TIMEBASE_DIVISOR = 11,
519 CYCLETIME = 12,
520
521 CAS_LATENCIES_LSB = 14,
522 CAS_LATENCIES_MSB = 15,
523 CAS_LATENCY_TIME = 16,
524 THERMAL_AND_REFRESH = 31,
525 REFERENCE_RAW_CARD_USED = 62,
526 RANK1_ADDRESS_MAPPING = 63
527};
528
529static void calculate_timings(struct raminfo *info)
530{
Martin Roth468d02c2019-10-23 21:44:42 -0600531 unsigned int cycletime;
532 unsigned int cas_latency_time;
533 unsigned int supported_cas_latencies;
534 unsigned int channel, slot;
535 unsigned int clock_speed_index;
536 unsigned int min_cas_latency;
537 unsigned int cas_latency;
538 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100539
540 /* Find common CAS latency */
541 supported_cas_latencies = 0x3fe;
542 for (channel = 0; channel < NUM_CHANNELS; channel++)
543 for (slot = 0; slot < NUM_SLOTS; slot++)
544 if (info->populated_ranks[channel][slot][0])
545 supported_cas_latencies &=
546 2 *
547 (info->
548 spd[channel][slot][CAS_LATENCIES_LSB] |
549 (info->
550 spd[channel][slot][CAS_LATENCIES_MSB] <<
551 8));
552
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100553 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100554
555 cycletime = min_cycletime[max_clock_index];
556 cas_latency_time = min_cas_latency_time[max_clock_index];
557
558 for (channel = 0; channel < NUM_CHANNELS; channel++)
559 for (slot = 0; slot < NUM_SLOTS; slot++)
560 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600561 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100562 timebase =
563 1000 *
564 info->
565 spd[channel][slot][TIMEBASE_DIVIDEND] /
566 info->spd[channel][slot][TIMEBASE_DIVISOR];
567 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100568 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100569 timebase *
570 info->spd[channel][slot][CYCLETIME]);
571 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100572 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100573 timebase *
574 info->
575 spd[channel][slot][CAS_LATENCY_TIME]);
576 }
Jacob Garber3c193822019-06-10 18:23:32 -0600577 if (cycletime > min_cycletime[0])
578 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100579 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
580 if (cycletime == min_cycletime[clock_speed_index])
581 break;
582 if (cycletime > min_cycletime[clock_speed_index]) {
583 clock_speed_index--;
584 cycletime = min_cycletime[clock_speed_index];
585 break;
586 }
587 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100588 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100589 cas_latency = 0;
590 while (supported_cas_latencies) {
591 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
592 if (cas_latency <= min_cas_latency)
593 break;
594 supported_cas_latencies &=
595 ~(1 << find_highest_bit_set(supported_cas_latencies));
596 }
597
598 if (cas_latency != min_cas_latency && clock_speed_index)
599 clock_speed_index--;
600
601 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
602 die("Couldn't configure DRAM");
603 info->clock_speed_index = clock_speed_index;
604 info->cas_latency = cas_latency;
605}
606
607static void program_base_timings(struct raminfo *info)
608{
Martin Roth468d02c2019-10-23 21:44:42 -0600609 unsigned int channel;
610 unsigned int slot, rank, lane;
611 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100612 int i;
613
614 extended_silicon_revision = info->silicon_revision;
615 if (info->silicon_revision == 0)
616 for (channel = 0; channel < NUM_CHANNELS; channel++)
617 for (slot = 0; slot < NUM_SLOTS; slot++)
618 if ((info->
619 spd[channel][slot][MODULE_TYPE] & 0xF) ==
620 3)
621 extended_silicon_revision = 4;
622
623 for (channel = 0; channel < NUM_CHANNELS; channel++) {
624 for (slot = 0; slot < NUM_SLOTS; slot++)
625 for (rank = 0; rank < NUM_SLOTS; rank++) {
626 int card_timing_2;
627 if (!info->populated_ranks[channel][slot][rank])
628 continue;
629
630 for (lane = 0; lane < 9; lane++) {
631 int tm_reg;
632 int card_timing;
633
634 card_timing = 0;
635 if ((info->
636 spd[channel][slot][MODULE_TYPE] &
637 0xF) == 3) {
638 int reference_card;
639 reference_card =
640 info->
641 spd[channel][slot]
642 [REFERENCE_RAW_CARD_USED] &
643 0x1f;
644 if (reference_card == 3)
645 card_timing =
646 u16_ffd1188[0][lane]
647 [info->
648 clock_speed_index];
649 if (reference_card == 5)
650 card_timing =
651 u16_ffd1188[1][lane]
652 [info->
653 clock_speed_index];
654 }
655
656 info->training.
657 lane_timings[0][channel][slot][rank]
658 [lane] =
659 u8_FFFD1218[info->
660 clock_speed_index];
661 info->training.
662 lane_timings[1][channel][slot][rank]
663 [lane] = 256;
664
665 for (tm_reg = 2; tm_reg < 4; tm_reg++)
666 info->training.
667 lane_timings[tm_reg]
668 [channel][slot][rank][lane]
669 =
670 u8_FFFD1240[channel]
671 [extended_silicon_revision]
672 [lane][2 * slot +
673 rank][info->
674 clock_speed_index]
675 + info->max4048[channel]
676 +
677 u8_FFFD0C78[channel]
678 [extended_silicon_revision]
679 [info->
680 mode4030[channel]][slot]
681 [rank][info->
682 clock_speed_index]
683 + card_timing;
684 for (tm_reg = 0; tm_reg < 4; tm_reg++)
685 write_500(info, channel,
686 info->training.
687 lane_timings[tm_reg]
688 [channel][slot][rank]
689 [lane],
690 get_timing_register_addr
691 (lane, tm_reg, slot,
692 rank), 9, 0);
693 }
694
695 card_timing_2 = 0;
696 if (!(extended_silicon_revision != 4
697 || (info->
698 populated_ranks_mask[channel] & 5) ==
699 5)) {
700 if ((info->
701 spd[channel][slot]
702 [REFERENCE_RAW_CARD_USED] & 0x1F)
703 == 3)
704 card_timing_2 =
705 u16_FFFE0EB8[0][info->
706 clock_speed_index];
707 if ((info->
708 spd[channel][slot]
709 [REFERENCE_RAW_CARD_USED] & 0x1F)
710 == 5)
711 card_timing_2 =
712 u16_FFFE0EB8[1][info->
713 clock_speed_index];
714 }
715
716 for (i = 0; i < 3; i++)
717 write_500(info, channel,
718 (card_timing_2 +
719 info->max4048[channel]
720 +
721 u8_FFFD0EF8[channel]
722 [extended_silicon_revision]
723 [info->
724 mode4030[channel]][info->
725 clock_speed_index]),
726 u16_fffd0c50[i][slot][rank],
727 8, 1);
728 write_500(info, channel,
729 (info->max4048[channel] +
730 u8_FFFD0C78[channel]
731 [extended_silicon_revision][info->
732 mode4030
733 [channel]]
734 [slot][rank][info->
735 clock_speed_index]),
736 u16_fffd0c70[slot][rank], 7, 1);
737 }
738 if (!info->populated_ranks_mask[channel])
739 continue;
740 for (i = 0; i < 3; i++)
741 write_500(info, channel,
742 (info->max4048[channel] +
743 info->avg4044[channel]
744 +
745 u8_FFFD17E0[channel]
746 [extended_silicon_revision][info->
747 mode4030
748 [channel]][info->
749 clock_speed_index]),
750 u16_fffd0c68[i], 8, 1);
751 }
752}
753
754static unsigned int fsbcycle_ps(struct raminfo *info)
755{
756 return 900000 / info->fsb_frequency;
757}
758
759/* The time of DDR transfer in ps. */
760static unsigned int halfcycle_ps(struct raminfo *info)
761{
762 return 3750 / (info->clock_speed_index + 3);
763}
764
765/* The time of clock cycle in ps. */
766static unsigned int cycle_ps(struct raminfo *info)
767{
768 return 2 * halfcycle_ps(info);
769}
770
771/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600772static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100773{
774 return (info->clock_speed_index + 3) * 120;
775}
776
777/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600778static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100779{
780 return 100 * frequency_11(info) / 9;
781}
782
Martin Roth468d02c2019-10-23 21:44:42 -0600783static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100784{
785 return (frequency_11(info) * 2) * ps / 900000;
786}
787
Martin Roth468d02c2019-10-23 21:44:42 -0600788static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100789{
790 return (frequency_11(info)) * ns / 900;
791}
792
793static void compute_derived_timings(struct raminfo *info)
794{
Martin Roth468d02c2019-10-23 21:44:42 -0600795 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100796 int extended_silicon_revision;
797 int some_delay_1_ps;
798 int some_delay_2_ps;
799 int some_delay_2_halfcycles_ceil;
800 int some_delay_2_halfcycles_floor;
801 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100802 int some_delay_3_ps_rounded;
803 int some_delay_1_cycle_ceil;
804 int some_delay_1_cycle_floor;
805
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100806 some_delay_3_ps_rounded = 0;
807 extended_silicon_revision = info->silicon_revision;
808 if (!info->silicon_revision)
809 for (channel = 0; channel < NUM_CHANNELS; channel++)
810 for (slot = 0; slot < NUM_SLOTS; slot++)
811 if ((info->
812 spd[channel][slot][MODULE_TYPE] & 0xF) ==
813 3)
814 extended_silicon_revision = 4;
815 if (info->board_lane_delay[7] < 5)
816 info->board_lane_delay[7] = 5;
817 info->revision_flag_1 = 2;
818 if (info->silicon_revision == 2 || info->silicon_revision == 3)
819 info->revision_flag_1 = 0;
820 if (info->revision < 16)
821 info->revision_flag_1 = 0;
822
823 if (info->revision < 8)
824 info->revision_flag_1 = 0;
825 if (info->revision >= 8 && (info->silicon_revision == 0
826 || info->silicon_revision == 1))
827 some_delay_2_ps = 735;
828 else
829 some_delay_2_ps = 750;
830
831 if (info->revision >= 0x10 && (info->silicon_revision == 0
832 || info->silicon_revision == 1))
833 some_delay_1_ps = 3929;
834 else
835 some_delay_1_ps = 3490;
836
837 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
838 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
839 if (some_delay_1_ps % cycle_ps(info))
840 some_delay_1_cycle_ceil++;
841 else
842 some_delay_1_cycle_floor--;
843 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
844 if (info->revision_flag_1)
845 some_delay_2_ps = halfcycle_ps(info) >> 6;
846 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100847 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100848 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
849 375;
850 some_delay_3_ps =
851 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
852 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200853 if (some_delay_3_ps >= 150) {
854 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100855 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200856 some_delay_3_ps_rounded =
857 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
858 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100859 }
860 some_delay_2_halfcycles_ceil =
861 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
862 2 * (some_delay_1_cycle_ceil - 1);
863 if (info->revision_flag_1 && some_delay_3_ps < 150)
864 some_delay_2_halfcycles_ceil++;
865 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
866 if (info->revision < 0x10)
867 some_delay_2_halfcycles_floor =
868 some_delay_2_halfcycles_ceil - 1;
869 if (!info->revision_flag_1)
870 some_delay_2_halfcycles_floor++;
871 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
872 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
873 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
874 || (info->populated_ranks[1][0][0]
875 && info->populated_ranks[1][1][0]))
876 info->max_slots_used_in_channel = 2;
877 else
878 info->max_slots_used_in_channel = 1;
879 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200880 MCHBAR32(0x244 + (channel << 10)) =
881 ((info->revision < 8) ? 1 : 0x200) |
882 ((2 - info->max_slots_used_in_channel) << 17) |
883 (channel << 21) |
884 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100885 if (info->max_slots_used_in_channel == 1) {
886 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
887 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
888 } else {
889 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 */
890 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
891 || (count_ranks_in_channel(info, 1) ==
892 2)) ? 2 : 3;
893 }
894 for (channel = 0; channel < NUM_CHANNELS; channel++) {
895 int max_of_unk;
896 int min_of_unk_2;
897
898 int i, count;
899 int sum;
900
901 if (!info->populated_ranks_mask[channel])
902 continue;
903
904 max_of_unk = 0;
905 min_of_unk_2 = 32767;
906
907 sum = 0;
908 count = 0;
909 for (i = 0; i < 3; i++) {
910 int unk1;
911 if (info->revision < 8)
912 unk1 =
913 u8_FFFD1891[0][channel][info->
914 clock_speed_index]
915 [i];
916 else if (!
917 (info->revision >= 0x10
918 || info->revision_flag_1))
919 unk1 =
920 u8_FFFD1891[1][channel][info->
921 clock_speed_index]
922 [i];
923 else
924 unk1 = 0;
925 for (slot = 0; slot < NUM_SLOTS; slot++)
926 for (rank = 0; rank < NUM_RANKS; rank++) {
927 int a = 0;
928 int b = 0;
929
930 if (!info->
931 populated_ranks[channel][slot]
932 [rank])
933 continue;
934 if (extended_silicon_revision == 4
935 && (info->
936 populated_ranks_mask[channel] &
937 5) != 5) {
938 if ((info->
939 spd[channel][slot]
940 [REFERENCE_RAW_CARD_USED] &
941 0x1F) == 3) {
942 a = u16_ffd1178[0]
943 [info->
944 clock_speed_index];
945 b = u16_fe0eb8[0][info->
946 clock_speed_index];
947 } else
948 if ((info->
949 spd[channel][slot]
950 [REFERENCE_RAW_CARD_USED]
951 & 0x1F) == 5) {
952 a = u16_ffd1178[1]
953 [info->
954 clock_speed_index];
955 b = u16_fe0eb8[1][info->
956 clock_speed_index];
957 }
958 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100959 min_of_unk_2 = MIN(min_of_unk_2, a);
960 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100961 if (rank == 0) {
962 sum += a;
963 count++;
964 }
965 {
966 int t;
967 t = b +
968 u8_FFFD0EF8[channel]
969 [extended_silicon_revision]
970 [info->
971 mode4030[channel]][info->
972 clock_speed_index];
973 if (unk1 >= t)
974 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100975 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100976 unk1 - t);
977 }
978 }
979 {
980 int t =
981 u8_FFFD17E0[channel]
982 [extended_silicon_revision][info->
983 mode4030
984 [channel]]
985 [info->clock_speed_index] + min_of_unk_2;
986 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100987 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100988 }
989 }
990
Jacob Garber64fb4a32019-06-10 17:29:18 -0600991 if (count == 0)
992 die("No memory ranks found for channel %u\n", channel);
993
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100994 info->avg4044[channel] = sum / count;
995 info->max4048[channel] = max_of_unk;
996 }
997}
998
999static void jedec_read(struct raminfo *info,
1000 int channel, int slot, int rank,
1001 int total_rank, u8 addr3, unsigned int value)
1002{
1003 /* Handle mirrored mapping. */
1004 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001005 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1006 ((addr3 >> 1) & 0x10);
1007 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1008 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001009
1010 /* Handle mirrored mapping. */
1011 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1012 value =
1013 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1014 << 1);
1015
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001016 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001017
Felix Held04be2dd2018-07-29 04:53:22 +02001018 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1019 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001020
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001021 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022}
1023
1024enum {
1025 MR1_RZQ12 = 512,
1026 MR1_RZQ2 = 64,
1027 MR1_RZQ4 = 4,
1028 MR1_ODS34OHM = 2
1029};
1030
1031enum {
1032 MR0_BT_INTERLEAVED = 8,
1033 MR0_DLL_RESET_ON = 256
1034};
1035
1036enum {
1037 MR2_RTT_WR_DISABLED = 0,
1038 MR2_RZQ2 = 1 << 10
1039};
1040
1041static void jedec_init(struct raminfo *info)
1042{
1043 int write_recovery;
1044 int channel, slot, rank;
1045 int total_rank;
1046 int dll_on;
1047 int self_refresh_temperature;
1048 int auto_self_refresh;
1049
1050 auto_self_refresh = 1;
1051 self_refresh_temperature = 1;
1052 if (info->board_lane_delay[3] <= 10) {
1053 if (info->board_lane_delay[3] <= 8)
1054 write_recovery = info->board_lane_delay[3] - 4;
1055 else
1056 write_recovery = 5;
1057 } else {
1058 write_recovery = 6;
1059 }
1060 FOR_POPULATED_RANKS {
1061 auto_self_refresh &=
1062 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1063 self_refresh_temperature &=
1064 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1065 }
1066 if (auto_self_refresh == 1)
1067 self_refresh_temperature = 0;
1068
1069 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1070 || (info->populated_ranks[0][0][0]
1071 && info->populated_ranks[0][1][0])
1072 || (info->populated_ranks[1][0][0]
1073 && info->populated_ranks[1][1][0]));
1074
1075 total_rank = 0;
1076
1077 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1078 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1079 int rzq_reg58e;
1080
1081 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1082 rzq_reg58e = 64;
1083 rtt = MR1_RZQ2;
1084 if (info->clock_speed_index != 0) {
1085 rzq_reg58e = 4;
1086 if (info->populated_ranks_mask[channel] == 3)
1087 rtt = MR1_RZQ4;
1088 }
1089 } else {
1090 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1091 rtt = MR1_RZQ12;
1092 rzq_reg58e = 64;
1093 rtt_wr = MR2_RZQ2;
1094 } else {
1095 rzq_reg58e = 4;
1096 rtt = MR1_RZQ4;
1097 }
1098 }
1099
Felix Held04be2dd2018-07-29 04:53:22 +02001100 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1101 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1102 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1103 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1104 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001105
1106 for (slot = 0; slot < NUM_SLOTS; slot++)
1107 for (rank = 0; rank < NUM_RANKS; rank++)
1108 if (info->populated_ranks[channel][slot][rank]) {
1109 jedec_read(info, channel, slot, rank,
1110 total_rank, 0x28,
1111 rtt_wr | (info->
1112 clock_speed_index
1113 << 3)
1114 | (auto_self_refresh << 6) |
1115 (self_refresh_temperature <<
1116 7));
1117 jedec_read(info, channel, slot, rank,
1118 total_rank, 0x38, 0);
1119 jedec_read(info, channel, slot, rank,
1120 total_rank, 0x18,
1121 rtt | MR1_ODS34OHM);
1122 jedec_read(info, channel, slot, rank,
1123 total_rank, 6,
1124 (dll_on << 12) |
1125 (write_recovery << 9)
1126 | ((info->cas_latency - 4) <<
1127 4) | MR0_BT_INTERLEAVED |
1128 MR0_DLL_RESET_ON);
1129 total_rank++;
1130 }
1131 }
1132}
1133
1134static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1135{
Martin Roth468d02c2019-10-23 21:44:42 -06001136 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001137 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1138 unsigned int channel_0_non_interleaved;
1139
1140 FOR_ALL_RANKS {
1141 if (info->populated_ranks[channel][slot][rank]) {
1142 total_mb[channel] +=
1143 pre_jedec ? 256 : (256 << info->
1144 density[channel][slot] >> info->
1145 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001146 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1147 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1148 (info->is_x16_module[channel][slot] |
1149 ((info->density[channel][slot] + 1) << 1))) |
1150 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001151 }
Felix Held04be2dd2018-07-29 04:53:22 +02001152 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1153 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001154 }
1155
1156 info->total_memory_mb = total_mb[0] + total_mb[1];
1157
1158 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001159 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001160 info->non_interleaved_part_mb =
1161 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1162 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001163 MCHBAR32(0x100) = channel_0_non_interleaved |
1164 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001165 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001166 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167}
1168
1169static void program_board_delay(struct raminfo *info)
1170{
1171 int cas_latency_shift;
1172 int some_delay_ns;
1173 int some_delay_3_half_cycles;
1174
Martin Roth468d02c2019-10-23 21:44:42 -06001175 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001176 int high_multiplier;
1177 int lane_3_delay;
1178 int cas_latency_derived;
1179
1180 high_multiplier = 0;
1181 some_delay_ns = 200;
1182 some_delay_3_half_cycles = 4;
1183 cas_latency_shift = info->silicon_revision == 0
1184 || info->silicon_revision == 1 ? 1 : 0;
1185 if (info->revision < 8) {
1186 some_delay_ns = 600;
1187 cas_latency_shift = 0;
1188 }
1189 {
1190 int speed_bit;
1191 speed_bit =
1192 ((info->clock_speed_index > 1
1193 || (info->silicon_revision != 2
1194 && info->silicon_revision != 3))) ^ (info->revision >=
1195 0x10);
1196 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1197 3, 1);
1198 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1199 3, 1);
1200 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1201 && (info->silicon_revision == 2
1202 || info->silicon_revision == 3))
1203 rmw_1d0(0x116, 5, 2, 4, 1);
1204 }
Felix Held04be2dd2018-07-29 04:53:22 +02001205 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1206 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001207
Felix Held04be2dd2018-07-29 04:53:22 +02001208 MCHBAR8(0x124) = info->board_lane_delay[4] +
1209 ((frequency_01(info) + 999) / 1000);
1210 MCHBAR16(0x125) = 0x1360;
1211 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001213 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214 high_multiplier = 1;
1215 some_delay_2_half_cycles = ps_to_halfcycles(info,
1216 ((3 *
1217 fsbcycle_ps(info))
1218 >> 1) +
1219 (halfcycle_ps(info)
1220 *
1221 reg178_min[info->
1222 clock_speed_index]
1223 >> 6)
1224 +
1225 4 *
1226 halfcycle_ps(info)
1227 + 2230);
1228 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001229 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230 (frequency_11(info) * 2) * (28 -
1231 some_delay_2_half_cycles) /
1232 (frequency_11(info) * 2 -
1233 4 * (info->fsb_frequency))) >> 3, 7);
1234 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001235 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001236 some_delay_3_half_cycles = 3;
1237 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001238 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1239 MCHBAR32(0x224 + (channel << 10)) =
1240 (info->max_slots_used_in_channel - 1) |
1241 ((info->cas_latency - 5 - info->clock_speed_index)
1242 << 21) | ((info->max_slots_used_in_channel +
1243 info->cas_latency - cas_latency_shift - 4) << 16) |
1244 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1245 ((info->cas_latency - info->clock_speed_index +
1246 info->max_slots_used_in_channel - 6) << 8);
1247 MCHBAR32(0x228 + (channel << 10)) =
1248 info->max_slots_used_in_channel;
1249 MCHBAR8(0x239 + (channel << 10)) = 32;
1250 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1251 (some_delay_3_half_cycles << 25) | 0x840000;
1252 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1253 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1254 MCHBAR32(0x24c + (channel << 10)) =
1255 ((!!info->clock_speed_index) << 17) |
1256 (((2 + info->clock_speed_index -
1257 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258
Felix Held04be2dd2018-07-29 04:53:22 +02001259 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1260 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1261 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001262
1263 write_500(info, channel,
1264 ((!info->populated_ranks[channel][1][1])
1265 | (!info->populated_ranks[channel][1][0] << 1)
1266 | (!info->populated_ranks[channel][0][1] << 2)
1267 | (!info->populated_ranks[channel][0][0] << 3)),
1268 0x4c9, 4, 1);
1269 }
1270
Felix Held22ca8cb2018-07-29 05:09:44 +02001271 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 {
1273 u8 freq_divisor = 2;
1274 if (info->fsb_frequency == frequency_11(info))
1275 freq_divisor = 3;
1276 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1277 freq_divisor = 1;
1278 else
1279 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001280 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001281 }
1282
1283 if (info->board_lane_delay[3] <= 10) {
1284 if (info->board_lane_delay[3] <= 8)
1285 lane_3_delay = info->board_lane_delay[3];
1286 else
1287 lane_3_delay = 10;
1288 } else {
1289 lane_3_delay = 12;
1290 }
1291 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1292 if (info->clock_speed_index > 1)
1293 cas_latency_derived++;
1294 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001295 MCHBAR32(0x240 + (channel << 10)) =
1296 ((info->clock_speed_index == 0) * 0x11000) |
1297 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1298 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001299 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1300 0x609, 6, 1);
1301 write_500(info, channel,
1302 info->clock_speed_index + 2 * info->cas_latency - 7,
1303 0x601, 6, 1);
1304
Felix Held04be2dd2018-07-29 04:53:22 +02001305 MCHBAR32(0x250 + (channel << 10)) =
1306 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1307 (info->board_lane_delay[7] << 2) |
1308 (info->board_lane_delay[4] << 16) |
1309 (info->board_lane_delay[1] << 25) |
1310 (info->board_lane_delay[1] << 29) | 1;
1311 MCHBAR32(0x254 + (channel << 10)) =
1312 (info->board_lane_delay[1] >> 3) |
1313 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1314 0x80 | (info->board_lane_delay[6] << 1) |
1315 (info->board_lane_delay[2] << 28) |
1316 (cas_latency_derived << 16) | 0x4700000;
1317 MCHBAR32(0x258 + (channel << 10)) =
1318 ((info->board_lane_delay[5] + info->clock_speed_index +
1319 9) << 12) | ((info->clock_speed_index -
1320 info->cas_latency + 12) << 8) |
1321 (info->board_lane_delay[2] << 17) |
1322 (info->board_lane_delay[4] << 24) | 0x47;
1323 MCHBAR32(0x25c + (channel << 10)) =
1324 (info->board_lane_delay[1] << 1) |
1325 (info->board_lane_delay[0] << 8) | 0x1da50000;
1326 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1327 MCHBAR8(0x5f8 + (channel << 10)) =
1328 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001329 }
1330
1331 program_modules_memory_map(info, 1);
1332
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001333 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001334 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1335 MCHBAR16_OR(0x612, 0x100);
1336 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001337 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001338 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001340 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341 }
1342}
1343
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001344#define DEFAULT_PCI_MMIO_SIZE 2048
1345#define HOST_BRIDGE PCI_DEVFN(0, 0)
1346
1347static unsigned int get_mmio_size(void)
1348{
1349 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001350 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001351
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001352 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001353 if (dev)
1354 cfg = dev->chip_info;
1355
1356 /* If this is zero, it just means devicetree.cb didn't set it */
1357 if (!cfg || cfg->pci_mmio_size == 0)
1358 return DEFAULT_PCI_MMIO_SIZE;
1359 else
1360 return cfg->pci_mmio_size;
1361}
1362
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363static void program_total_memory_map(struct raminfo *info)
1364{
Angel Pons9333b742020-07-22 16:04:15 +02001365 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001366 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001367 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001368 unsigned int uma_base_igd;
1369 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001370 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001371 int memory_remap;
1372 unsigned int memory_map[8];
1373 int i;
1374 unsigned int current_limit;
1375 unsigned int tseg_base;
1376 int uma_size_igd = 0, uma_size_gtt = 0;
1377
1378 memset(memory_map, 0, sizeof(memory_map));
1379
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001380 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001381 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001382 gav(t);
1383 const int uma_sizes_gtt[16] =
1384 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1385 /* Igd memory */
1386 const int uma_sizes_igd[16] = {
1387 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1388 256, 512
1389 };
1390
1391 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1392 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1393 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001394
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001395 mmio_size = get_mmio_size();
1396
Angel Pons9333b742020-07-22 16:04:15 +02001397 tom = info->total_memory_mb;
1398 if (tom == 4096)
1399 tom = 4032;
1400 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1401 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1402 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001404 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001406 remap_base = MAX(4096, touud);
1407 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001408 }
Angel Pons9333b742020-07-22 16:04:15 +02001409 if (touud > 4096)
1410 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001411 quickpath_reserved = 0;
1412
Angel Pons3ab19b32020-07-22 16:29:54 +02001413 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001414
Jacob Garber975a7e32019-06-10 16:32:47 -06001415 gav(t);
1416
1417 if (t & 0x800) {
1418 u32 shift = t >> 20;
1419 if (shift == 0)
1420 die("Quickpath value is 0\n");
1421 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001423
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001425 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426
Angel Pons9333b742020-07-22 16:04:15 +02001427 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001428 uma_base_gtt = uma_base_igd - uma_size_gtt;
1429 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1430 if (!memory_remap)
1431 tseg_base -= quickpath_reserved;
1432 tseg_base = ALIGN_DOWN(tseg_base, 8);
1433
Angel Pons16fe1e02020-07-22 16:12:33 +02001434 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1435 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001437 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1438 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001440 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001441
1442 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001443 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1444 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001446 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447
1448 current_limit = 0;
1449 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1450 memory_map[1] = 4096;
1451 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001452 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001453 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1455 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001456 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 }
1458}
1459
1460static void collect_system_info(struct raminfo *info)
1461{
1462 u32 capid0[3];
1463 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001464 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465
1466 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001467 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1468 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 if (!info->memory_reserved_for_heci_mb) {
1471 /* Wait for ME to be ready */
1472 intel_early_me_init();
1473 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1474 }
1475
1476 for (i = 0; i < 3; i++)
1477 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001478 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001479 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1481
1482 if ((capid0[1] >> 11) & 1)
1483 info->uma_enabled = 0;
1484 else
1485 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001486 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1488 info->silicon_revision = 0;
1489
1490 if (capid0[2] & 2) {
1491 info->silicon_revision = 0;
1492 info->max_supported_clock_speed_index = 2;
1493 for (channel = 0; channel < NUM_CHANNELS; channel++)
1494 if (info->populated_ranks[channel][0][0]
1495 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1496 3) {
1497 info->silicon_revision = 2;
1498 info->max_supported_clock_speed_index = 1;
1499 }
1500 } else {
1501 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1502 case 1:
1503 case 2:
1504 info->silicon_revision = 3;
1505 break;
1506 case 3:
1507 info->silicon_revision = 0;
1508 break;
1509 case 0:
1510 info->silicon_revision = 2;
1511 break;
1512 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001513 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001514 case 0x40:
1515 info->silicon_revision = 0;
1516 break;
1517 case 0x48:
1518 info->silicon_revision = 1;
1519 break;
1520 }
1521 }
1522}
1523
1524static void write_training_data(struct raminfo *info)
1525{
1526 int tm, channel, slot, rank, lane;
1527 if (info->revision < 8)
1528 return;
1529
1530 for (tm = 0; tm < 4; tm++)
1531 for (channel = 0; channel < NUM_CHANNELS; channel++)
1532 for (slot = 0; slot < NUM_SLOTS; slot++)
1533 for (rank = 0; rank < NUM_RANKS; rank++)
1534 for (lane = 0; lane < 9; lane++)
1535 write_500(info, channel,
1536 info->
1537 cached_training->
1538 lane_timings[tm]
1539 [channel][slot][rank]
1540 [lane],
1541 get_timing_register_addr
1542 (lane, tm, slot,
1543 rank), 9, 0);
1544 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1545 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1546}
1547
1548static void dump_timings(struct raminfo *info)
1549{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001550 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001551 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001552 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001553 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001554 slot, rank);
1555 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001556 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001558 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559 read_500(info, channel,
1560 get_timing_register_addr
1561 (lane, i, slot, rank),
1562 9),
1563 info->training.
1564 lane_timings[i][channel][slot][rank]
1565 [lane]);
1566 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001567 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568 }
1569 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001570 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001571 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001572 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574}
1575
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001576/* Read timings and other registers that need to be restored verbatim and
1577 put them to CBMEM.
1578 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579static void save_timings(struct raminfo *info)
1580{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 int channel, slot, rank, lane, i;
1583
1584 train = info->training;
1585 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1586 for (i = 0; i < 4; i++)
1587 train.lane_timings[i][channel][slot][rank][lane] =
1588 read_500(info, channel,
1589 get_timing_register_addr(lane, i, slot,
1590 rank), 9);
1591 train.reg_178 = read_1d0(0x178, 7);
1592 train.reg_10b = read_1d0(0x10b, 6);
1593
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001594 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1595 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001596 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001597 train.reg274265[channel][0] = reg32 >> 16;
1598 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001599 train.reg274265[channel][2] =
1600 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001601 }
Felix Held04be2dd2018-07-29 04:53:22 +02001602 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1603 train.reg_6dc = MCHBAR32(0x6dc);
1604 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001605
Arthur Heymansb3282092019-04-14 17:53:28 +02001606 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1607 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001608
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001609 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001610 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1611 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001612}
1613
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001614static const struct ram_training *get_cached_training(void)
1615{
Shelley Chenad9cd682020-07-23 16:10:52 -07001616 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1617 MRC_CACHE_VERSION,
1618 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001619}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620
1621/* FIXME: add timeout. */
1622static void wait_heci_ready(void)
1623{
Felix Held04be2dd2018-07-29 04:53:22 +02001624 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1625 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001626 write32((DEFAULT_HECIBAR + 0x4),
1627 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628}
1629
1630/* FIXME: add timeout. */
1631static void wait_heci_cb_avail(int len)
1632{
1633 union {
1634 struct mei_csr csr;
1635 u32 raw;
1636 } csr;
1637
Felix Held22ca8cb2018-07-29 05:09:44 +02001638 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1639 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640
1641 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001642 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643 while (len >
1644 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001645 csr.csr.buffer_read_ptr))
1646 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647}
1648
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001649static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650{
1651 int len = (head->length + 3) / 4;
1652 int i;
1653
1654 wait_heci_cb_avail(len + 1);
1655
1656 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001657 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001658 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001659 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001660
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001661 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1662 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663}
1664
1665static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001666send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667{
1668 struct mei_header head;
1669 int maxlen;
1670
1671 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001672 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673
1674 while (len) {
1675 int cur = len;
1676 if (cur > maxlen) {
1677 cur = maxlen;
1678 head.is_complete = 0;
1679 } else
1680 head.is_complete = 1;
1681 head.length = cur;
1682 head.reserved = 0;
1683 head.client_address = clientaddress;
1684 head.host_address = hostaddress;
1685 send_heci_packet(&head, (u32 *) msg);
1686 len -= cur;
1687 msg += cur;
1688 }
1689}
1690
1691/* FIXME: Add timeout. */
1692static int
Angel Pons86907462020-09-14 18:48:59 +02001693recv_heci_packet(struct mei_header *head, u32 *packet,
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001694 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695{
1696 union {
1697 struct mei_csr csr;
1698 u32 raw;
1699 } csr;
1700 int i = 0;
1701
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001702 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001703 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001704 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705 }
Felix Held04be2dd2018-07-29 04:53:22 +02001706 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1707 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001708 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001710 write32(DEFAULT_HECIBAR + 0x4,
1711 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001712 *packet_size = 0;
1713 return 0;
1714 }
1715 if (head->length + 4 > 4 * csr.csr.buffer_depth
1716 || head->length > *packet_size) {
1717 *packet_size = 0;
1718 return -1;
1719 }
1720
1721 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001722 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001723 while (((head->length + 3) >> 2) >
1724 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1725 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726
1727 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001728 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729 *packet_size = head->length;
1730 if (!csr.csr.ready)
1731 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001732 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733 return 0;
1734}
1735
1736/* FIXME: Add timeout. */
1737static int
Angel Pons86907462020-09-14 18:48:59 +02001738recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739{
1740 struct mei_header head;
1741 int current_position;
1742
1743 current_position = 0;
1744 while (1) {
1745 u32 current_size;
1746 current_size = *message_size - current_position;
1747 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001748 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001749 &current_size) == -1)
1750 break;
1751 if (!current_size)
1752 break;
1753 current_position += current_size;
1754 if (head.is_complete) {
1755 *message_size = current_position;
1756 return 0;
1757 }
1758
1759 if (current_position >= *message_size)
1760 break;
1761 }
1762 *message_size = 0;
1763 return -1;
1764}
1765
Angel Pons55f11e22020-09-14 19:06:53 +02001766static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001767{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001768 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001769 u8 group_id;
1770 u8 command;
1771 u8 reserved;
1772 u8 result;
1773 u8 field2;
1774 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001775 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001776
1777 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1778 reply.command = 0;
1779
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001780 struct uma_message {
1781 u8 group_id;
1782 u8 cmd;
1783 u8 reserved;
1784 u8 result;
1785 u32 c2;
1786 u64 heci_uma_addr;
1787 u32 memory_reserved_for_heci_mb;
1788 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001789 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001790 0, MKHI_SET_UMA, 0, 0,
1791 0x82,
Angel Pons55f11e22020-09-14 19:06:53 +02001792 heci_uma_addr, heci_uma_size, 0};
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001793 u32 reply_size;
1794
1795 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1796
1797 reply_size = sizeof(reply);
Angel Pons86907462020-09-14 18:48:59 +02001798 if (recv_heci_message((u32 *) & reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001799 return;
1800
1801 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1802 die("HECI init failed\n");
1803}
1804
1805static void setup_heci_uma(struct raminfo *info)
1806{
Angel Pons298d34d2020-09-14 18:58:53 +02001807 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001808 return;
1809
Angel Pons36592bf2020-09-14 18:52:44 +02001810 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001811 ((u64)
Angel Pons16fe1e02020-07-22 16:12:33 +02001812 ((((u64) pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001813 info->memory_reserved_for_heci_mb)) << 20;
1814
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001815 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001816 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001817 write32(DEFAULT_DMIBAR + 0x14,
1818 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1819 write32(DEFAULT_RCBA + 0x14,
1820 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1821 write32(DEFAULT_DMIBAR + 0x20,
1822 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1823 write32(DEFAULT_RCBA + 0x20,
1824 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1825 write32(DEFAULT_DMIBAR + 0x2c,
1826 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1827 write32(DEFAULT_RCBA + 0x30,
1828 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1829 write32(DEFAULT_DMIBAR + 0x38,
1830 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1831 write32(DEFAULT_RCBA + 0x40,
1832 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001834 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1835 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001836 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1837 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1838 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 }
1840
Felix Held04be2dd2018-07-29 04:53:22 +02001841 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842
Angel Pons55f11e22020-09-14 19:06:53 +02001843 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001845 pci_write_config32(HECIDEV, 0x10, 0x0);
1846 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847
1848}
1849
1850static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1851{
1852 int ranks_in_channel;
1853 ranks_in_channel = info->populated_ranks[channel][0][0]
1854 + info->populated_ranks[channel][0][1]
1855 + info->populated_ranks[channel][1][0]
1856 + info->populated_ranks[channel][1][1];
1857
1858 /* empty channel */
1859 if (ranks_in_channel == 0)
1860 return 1;
1861
1862 if (ranks_in_channel != ranks)
1863 return 0;
1864 /* single slot */
1865 if (info->populated_ranks[channel][0][0] !=
1866 info->populated_ranks[channel][1][0])
1867 return 1;
1868 if (info->populated_ranks[channel][0][1] !=
1869 info->populated_ranks[channel][1][1])
1870 return 1;
1871 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1872 return 0;
1873 if (info->density[channel][0] != info->density[channel][1])
1874 return 0;
1875 return 1;
1876}
1877
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001878static void read_4090(struct raminfo *info)
1879{
1880 int i, channel, slot, rank, lane;
1881 for (i = 0; i < 2; i++)
1882 for (slot = 0; slot < NUM_SLOTS; slot++)
1883 for (rank = 0; rank < NUM_RANKS; rank++)
1884 for (lane = 0; lane < 9; lane++)
1885 info->training.
1886 lane_timings[0][i][slot][rank][lane]
1887 = 32;
1888
1889 for (i = 1; i < 4; i++)
1890 for (channel = 0; channel < NUM_CHANNELS; channel++)
1891 for (slot = 0; slot < NUM_SLOTS; slot++)
1892 for (rank = 0; rank < NUM_RANKS; rank++)
1893 for (lane = 0; lane < 9; lane++) {
1894 info->training.
1895 lane_timings[i][channel]
1896 [slot][rank][lane] =
1897 read_500(info, channel,
1898 get_timing_register_addr
1899 (lane, i, slot,
1900 rank), 9)
1901 + (i == 1) * 11; // !!!!
1902 }
1903
1904}
1905
1906static u32 get_etalon2(int flip, u32 addr)
1907{
1908 const u16 invmask[] = {
1909 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1910 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1911 };
1912 u32 ret;
1913 u32 comp4 = addr / 480;
1914 addr %= 480;
1915 u32 comp1 = addr & 0xf;
1916 u32 comp2 = (addr >> 4) & 1;
1917 u32 comp3 = addr >> 5;
1918
1919 if (comp4)
1920 ret = 0x1010101 << (comp4 - 1);
1921 else
1922 ret = 0;
1923 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1924 ret = ~ret;
1925
1926 return ret;
1927}
1928
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001929static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001930{
1931 msr_t msr = {.lo = 0, .hi = 0 };
1932
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001933 wrmsr(MTRR_PHYS_BASE(3), msr);
1934 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001935}
1936
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001937static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001938{
1939 msr_t msr;
1940 msr.lo = base | MTRR_TYPE_WRPROT;
1941 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001942 wrmsr(MTRR_PHYS_BASE(3), msr);
1943 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001944 & 0xffffffff);
1945 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001946 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001947}
1948
1949static void flush_cache(u32 start, u32 size)
1950{
1951 u32 end;
1952 u32 addr;
1953
1954 end = start + (ALIGN_DOWN(size + 4096, 4096));
1955 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001956 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001957}
1958
1959static void clear_errors(void)
1960{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001961 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001962}
1963
1964static void write_testing(struct raminfo *info, int totalrank, int flip)
1965{
1966 int nwrites = 0;
1967 /* in 8-byte units. */
1968 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001969 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001971 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972 for (offset = 0; offset < 9 * 480; offset += 2) {
1973 write32(base + offset * 8, get_etalon2(flip, offset));
1974 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1975 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1976 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1977 nwrites += 4;
1978 if (nwrites >= 320) {
1979 clear_errors();
1980 nwrites = 0;
1981 }
1982 }
1983}
1984
1985static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1986{
1987 u8 failmask = 0;
1988 int i;
1989 int comp1, comp2, comp3;
1990 u32 failxor[2] = { 0, 0 };
1991
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001992 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001993
1994 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1995 for (comp1 = 0; comp1 < 4; comp1++)
1996 for (comp2 = 0; comp2 < 60; comp2++) {
1997 u32 re[4];
1998 u32 curroffset =
1999 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2000 read128((total_rank << 28) | (curroffset << 3),
2001 (u64 *) re);
2002 failxor[0] |=
2003 get_etalon2(flip, curroffset) ^ re[0];
2004 failxor[1] |=
2005 get_etalon2(flip, curroffset) ^ re[1];
2006 failxor[0] |=
2007 get_etalon2(flip, curroffset | 1) ^ re[2];
2008 failxor[1] |=
2009 get_etalon2(flip, curroffset | 1) ^ re[3];
2010 }
2011 for (i = 0; i < 8; i++)
2012 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2013 failmask |= 1 << i;
2014 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002015 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002016 flush_cache((total_rank << 28), 1728 * 5 * 4);
2017 return failmask;
2018}
2019
2020const u32 seed1[0x18] = {
2021 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2022 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2023 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2024 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2025 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2026 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2027};
2028
2029static u32 get_seed2(int a, int b)
2030{
2031 const u32 seed2[5] = {
2032 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2033 0x5b6db6db,
2034 };
2035 u32 r;
2036 r = seed2[(a + (a >= 10)) / 5];
2037 return b ? ~r : r;
2038}
2039
2040static int make_shift(int comp2, int comp5, int x)
2041{
2042 const u8 seed3[32] = {
2043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2044 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2045 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2046 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2047 };
2048
2049 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2050}
2051
2052static u32 get_etalon(int flip, u32 addr)
2053{
2054 u32 mask_byte = 0;
2055 int comp1 = (addr >> 1) & 1;
2056 int comp2 = (addr >> 3) & 0x1f;
2057 int comp3 = (addr >> 8) & 0xf;
2058 int comp4 = (addr >> 12) & 0xf;
2059 int comp5 = (addr >> 16) & 0x1f;
2060 u32 mask_bit = ~(0x10001 << comp3);
2061 u32 part1;
2062 u32 part2;
2063 int byte;
2064
2065 part2 =
2066 ((seed1[comp5] >>
2067 make_shift(comp2, comp5,
2068 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2069 part1 =
2070 ((seed1[comp5] >>
2071 make_shift(comp2, comp5,
2072 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2073
2074 for (byte = 0; byte < 4; byte++)
2075 if ((get_seed2(comp5, comp4) >>
2076 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2077 mask_byte |= 0xff << (8 * byte);
2078
2079 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2080 (comp3 + 16));
2081}
2082
2083static void
2084write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2085 char flip)
2086{
2087 int i;
2088 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002089 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2090 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002091}
2092
2093static u8
2094check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2095 char flip)
2096{
2097 u8 failmask = 0;
2098 u32 failxor[2];
2099 int i;
2100 int comp1, comp2, comp3;
2101
2102 failxor[0] = 0;
2103 failxor[1] = 0;
2104
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002105 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002106 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2107 for (comp1 = 0; comp1 < 16; comp1++)
2108 for (comp2 = 0; comp2 < 64; comp2++) {
2109 u32 addr =
2110 (totalrank << 28) | (region << 25) | (block
2111 << 16)
2112 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2113 2);
2114 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002115 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002116 }
2117 for (i = 0; i < 8; i++)
2118 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2119 failmask |= 1 << i;
2120 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002121 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002122 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2123 return failmask;
2124}
2125
2126static int check_bounded(unsigned short *vals, u16 bound)
2127{
2128 int i;
2129
2130 for (i = 0; i < 8; i++)
2131 if (vals[i] < bound)
2132 return 0;
2133 return 1;
2134}
2135
2136enum state {
2137 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2138};
2139
2140static int validate_state(enum state *in)
2141{
2142 int i;
2143 for (i = 0; i < 8; i++)
2144 if (in[i] != COMPLETE)
2145 return 0;
2146 return 1;
2147}
2148
2149static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002150do_fsm(enum state *state, u16 *counter,
2151 u8 fail_mask, int margin, int uplimit,
2152 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002153{
2154 int lane;
2155
2156 for (lane = 0; lane < 8; lane++) {
2157 int is_fail = (fail_mask >> lane) & 1;
2158 switch (state[lane]) {
2159 case BEFORE_USABLE:
2160 if (!is_fail) {
2161 counter[lane] = 1;
2162 state[lane] = AT_USABLE;
2163 break;
2164 }
2165 counter[lane] = 0;
2166 state[lane] = BEFORE_USABLE;
2167 break;
2168 case AT_USABLE:
2169 if (!is_fail) {
2170 ++counter[lane];
2171 if (counter[lane] >= margin) {
2172 state[lane] = AT_MARGIN;
2173 res_low[lane] = val - margin + 1;
2174 break;
2175 }
2176 state[lane] = 1;
2177 break;
2178 }
2179 counter[lane] = 0;
2180 state[lane] = BEFORE_USABLE;
2181 break;
2182 case AT_MARGIN:
2183 if (is_fail) {
2184 state[lane] = COMPLETE;
2185 res_high[lane] = val - 1;
2186 } else {
2187 counter[lane]++;
2188 state[lane] = AT_MARGIN;
2189 if (val == uplimit) {
2190 state[lane] = COMPLETE;
2191 res_high[lane] = uplimit;
2192 }
2193 }
2194 break;
2195 case COMPLETE:
2196 break;
2197 }
2198 }
2199}
2200
2201static void
2202train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2203 u8 total_rank, u8 reg_178, int first_run, int niter,
2204 timing_bounds_t * timings)
2205{
2206 int lane;
2207 enum state state[8];
2208 u16 count[8];
2209 u8 lower_usable[8];
2210 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002211 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002212 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002213 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002214
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002215 for (i = 0; i < 8; i++)
2216 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002217
2218 if (!first_run) {
2219 int is_all_ok = 1;
2220 for (lane = 0; lane < 8; lane++)
2221 if (timings[reg_178][channel][slot][rank][lane].
2222 smallest ==
2223 timings[reg_178][channel][slot][rank][lane].
2224 largest) {
2225 timings[reg_178][channel][slot][rank][lane].
2226 smallest = 0;
2227 timings[reg_178][channel][slot][rank][lane].
2228 largest = 0;
2229 is_all_ok = 0;
2230 }
2231 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002232 for (i = 0; i < 8; i++)
2233 state[i] = COMPLETE;
2234 }
2235 }
2236
2237 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2238 u8 failmask = 0;
2239 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2240 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2241 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002242 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002243 do_fsm(state, count, failmask, 5, 47, lower_usable,
2244 upper_usable, reg1b3);
2245 }
2246
2247 if (reg1b3) {
2248 write_1d0(0, 0x1b3, 6, 1);
2249 write_1d0(0, 0x1a3, 6, 1);
2250 for (lane = 0; lane < 8; lane++) {
2251 if (state[lane] == COMPLETE) {
2252 timings[reg_178][channel][slot][rank][lane].
2253 smallest =
2254 lower_usable[lane] +
2255 (info->training.
2256 lane_timings[0][channel][slot][rank][lane]
2257 & 0x3F) - 32;
2258 timings[reg_178][channel][slot][rank][lane].
2259 largest =
2260 upper_usable[lane] +
2261 (info->training.
2262 lane_timings[0][channel][slot][rank][lane]
2263 & 0x3F) - 32;
2264 }
2265 }
2266 }
2267
2268 if (!first_run) {
2269 for (lane = 0; lane < 8; lane++)
2270 if (state[lane] == COMPLETE) {
2271 write_500(info, channel,
2272 timings[reg_178][channel][slot][rank]
2273 [lane].smallest,
2274 get_timing_register_addr(lane, 0,
2275 slot, rank),
2276 9, 1);
2277 write_500(info, channel,
2278 timings[reg_178][channel][slot][rank]
2279 [lane].smallest +
2280 info->training.
2281 lane_timings[1][channel][slot][rank]
2282 [lane]
2283 -
2284 info->training.
2285 lane_timings[0][channel][slot][rank]
2286 [lane], get_timing_register_addr(lane,
2287 1,
2288 slot,
2289 rank),
2290 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002291 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002292 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002293 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002294
2295 do {
2296 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002297 for (i = 0; i < niter; i++) {
2298 if (failmask == 0xFF)
2299 break;
2300 failmask |=
2301 check_testing_type2(info, total_rank, 2, i,
2302 0);
2303 failmask |=
2304 check_testing_type2(info, total_rank, 3, i,
2305 1);
2306 }
Felix Held04be2dd2018-07-29 04:53:22 +02002307 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002309 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002310 if ((1 << lane) & failmask) {
2311 if (timings[reg_178][channel]
2312 [slot][rank][lane].
2313 largest <=
2314 timings[reg_178][channel]
2315 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002316 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002317 [lane] = -1;
2318 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002319 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002320 [lane] = 0;
2321 timings[reg_178]
2322 [channel][slot]
2323 [rank][lane].
2324 smallest++;
2325 write_500(info, channel,
2326 timings
2327 [reg_178]
2328 [channel]
2329 [slot][rank]
2330 [lane].
2331 smallest,
2332 get_timing_register_addr
2333 (lane, 0,
2334 slot, rank),
2335 9, 1);
2336 write_500(info, channel,
2337 timings
2338 [reg_178]
2339 [channel]
2340 [slot][rank]
2341 [lane].
2342 smallest +
2343 info->
2344 training.
2345 lane_timings
2346 [1][channel]
2347 [slot][rank]
2348 [lane]
2349 -
2350 info->
2351 training.
2352 lane_timings
2353 [0][channel]
2354 [slot][rank]
2355 [lane],
2356 get_timing_register_addr
2357 (lane, 1,
2358 slot, rank),
2359 9, 1);
2360 }
2361 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002362 num_successfully_checked[lane]
2363 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002364 }
2365 }
Felix Held04be2dd2018-07-29 04:53:22 +02002366 while (!check_bounded(num_successfully_checked, 2))
2367 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002368
2369 for (lane = 0; lane < 8; lane++)
2370 if (state[lane] == COMPLETE) {
2371 write_500(info, channel,
2372 timings[reg_178][channel][slot][rank]
2373 [lane].largest,
2374 get_timing_register_addr(lane, 0,
2375 slot, rank),
2376 9, 1);
2377 write_500(info, channel,
2378 timings[reg_178][channel][slot][rank]
2379 [lane].largest +
2380 info->training.
2381 lane_timings[1][channel][slot][rank]
2382 [lane]
2383 -
2384 info->training.
2385 lane_timings[0][channel][slot][rank]
2386 [lane], get_timing_register_addr(lane,
2387 1,
2388 slot,
2389 rank),
2390 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002391 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002392 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002393 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002394
2395 do {
2396 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397 for (i = 0; i < niter; i++) {
2398 if (failmask == 0xFF)
2399 break;
2400 failmask |=
2401 check_testing_type2(info, total_rank, 2, i,
2402 0);
2403 failmask |=
2404 check_testing_type2(info, total_rank, 3, i,
2405 1);
2406 }
2407
Felix Held04be2dd2018-07-29 04:53:22 +02002408 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002409 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002410 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002411 if ((1 << lane) & failmask) {
2412 if (timings[reg_178][channel]
2413 [slot][rank][lane].
2414 largest <=
2415 timings[reg_178][channel]
2416 [slot][rank][lane].
2417 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002418 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002419 [lane] = -1;
2420 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002421 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002422 [lane] = 0;
2423 timings[reg_178]
2424 [channel][slot]
2425 [rank][lane].
2426 largest--;
2427 write_500(info, channel,
2428 timings
2429 [reg_178]
2430 [channel]
2431 [slot][rank]
2432 [lane].
2433 largest,
2434 get_timing_register_addr
2435 (lane, 0,
2436 slot, rank),
2437 9, 1);
2438 write_500(info, channel,
2439 timings
2440 [reg_178]
2441 [channel]
2442 [slot][rank]
2443 [lane].
2444 largest +
2445 info->
2446 training.
2447 lane_timings
2448 [1][channel]
2449 [slot][rank]
2450 [lane]
2451 -
2452 info->
2453 training.
2454 lane_timings
2455 [0][channel]
2456 [slot][rank]
2457 [lane],
2458 get_timing_register_addr
2459 (lane, 1,
2460 slot, rank),
2461 9, 1);
2462 }
2463 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002464 num_successfully_checked[lane]
2465 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002466 }
2467 }
2468 }
Felix Held04be2dd2018-07-29 04:53:22 +02002469 while (!check_bounded(num_successfully_checked, 3))
2470 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002471
2472 for (lane = 0; lane < 8; lane++) {
2473 write_500(info, channel,
2474 info->training.
2475 lane_timings[0][channel][slot][rank][lane],
2476 get_timing_register_addr(lane, 0, slot, rank),
2477 9, 1);
2478 write_500(info, channel,
2479 info->training.
2480 lane_timings[1][channel][slot][rank][lane],
2481 get_timing_register_addr(lane, 1, slot, rank),
2482 9, 1);
2483 if (timings[reg_178][channel][slot][rank][lane].
2484 largest <=
2485 timings[reg_178][channel][slot][rank][lane].
2486 smallest) {
2487 timings[reg_178][channel][slot][rank][lane].
2488 largest = 0;
2489 timings[reg_178][channel][slot][rank][lane].
2490 smallest = 0;
2491 }
2492 }
2493 }
2494}
2495
2496static void set_10b(struct raminfo *info, u8 val)
2497{
2498 int channel;
2499 int slot, rank;
2500 int lane;
2501
2502 if (read_1d0(0x10b, 6) == val)
2503 return;
2504
2505 write_1d0(val, 0x10b, 6, 1);
2506
2507 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2508 u16 reg_500;
2509 reg_500 = read_500(info, channel,
2510 get_timing_register_addr(lane, 0, slot,
2511 rank), 9);
2512 if (val == 1) {
2513 if (lut16[info->clock_speed_index] <= reg_500)
2514 reg_500 -= lut16[info->clock_speed_index];
2515 else
2516 reg_500 = 0;
2517 } else {
2518 reg_500 += lut16[info->clock_speed_index];
2519 }
2520 write_500(info, channel, reg_500,
2521 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2522 }
2523}
2524
2525static void set_ecc(int onoff)
2526{
2527 int channel;
2528 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2529 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002530 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002531 if (onoff)
2532 t |= 1;
2533 else
2534 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002535 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002536 }
2537}
2538
2539static void set_178(u8 val)
2540{
2541 if (val >= 31)
2542 val = val - 31;
2543 else
2544 val = 63 - val;
2545
2546 write_1d0(2 * val, 0x178, 7, 1);
2547}
2548
2549static void
2550write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2551 int type)
2552{
2553 int lane;
2554
2555 for (lane = 0; lane < 8; lane++)
2556 write_500(info, channel,
2557 info->training.
2558 lane_timings[type][channel][slot][rank][lane],
2559 get_timing_register_addr(lane, type, slot, rank), 9,
2560 0);
2561}
2562
2563static void
2564try_timing_offsets(struct raminfo *info, int channel,
2565 int slot, int rank, int totalrank)
2566{
2567 u16 count[8];
2568 enum state state[8];
2569 u8 lower_usable[8], upper_usable[8];
2570 int lane;
2571 int i;
2572 int flip = 1;
2573 int timing_offset;
2574
2575 for (i = 0; i < 8; i++)
2576 state[i] = BEFORE_USABLE;
2577
2578 memset(count, 0, sizeof(count));
2579
2580 for (lane = 0; lane < 8; lane++)
2581 write_500(info, channel,
2582 info->training.
2583 lane_timings[2][channel][slot][rank][lane] + 32,
2584 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2585
2586 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2587 timing_offset++) {
2588 u8 failmask;
2589 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2590 failmask = 0;
2591 for (i = 0; i < 2 && failmask != 0xff; i++) {
2592 flip = !flip;
2593 write_testing(info, totalrank, flip);
2594 failmask |= check_testing(info, totalrank, flip);
2595 }
2596 do_fsm(state, count, failmask, 10, 63, lower_usable,
2597 upper_usable, timing_offset);
2598 }
2599 write_1d0(0, 0x1bb, 6, 1);
2600 dump_timings(info);
2601 if (!validate_state(state))
2602 die("Couldn't discover DRAM timings (1)\n");
2603
2604 for (lane = 0; lane < 8; lane++) {
2605 u8 bias = 0;
2606
2607 if (info->silicon_revision) {
2608 int usable_length;
2609
2610 usable_length = upper_usable[lane] - lower_usable[lane];
2611 if (usable_length >= 20) {
2612 bias = usable_length / 2 - 10;
2613 if (bias >= 2)
2614 bias = 2;
2615 }
2616 }
2617 write_500(info, channel,
2618 info->training.
2619 lane_timings[2][channel][slot][rank][lane] +
2620 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2621 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2622 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2623 info->training.lane_timings[2][channel][slot][rank][lane] +
2624 lower_usable[lane];
2625 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2626 info->training.lane_timings[2][channel][slot][rank][lane] +
2627 upper_usable[lane];
2628 info->training.timing2_offset[channel][slot][rank][lane] =
2629 info->training.lane_timings[2][channel][slot][rank][lane];
2630 }
2631}
2632
2633static u8
2634choose_training(struct raminfo *info, int channel, int slot, int rank,
2635 int lane, timing_bounds_t * timings, u8 center_178)
2636{
2637 u16 central_weight;
2638 u16 side_weight;
2639 unsigned int sum = 0, count = 0;
2640 u8 span;
2641 u8 lower_margin, upper_margin;
2642 u8 reg_178;
2643 u8 result;
2644
2645 span = 12;
2646 central_weight = 20;
2647 side_weight = 20;
2648 if (info->silicon_revision == 1 && channel == 1) {
2649 central_weight = 5;
2650 side_weight = 20;
2651 if ((info->
2652 populated_ranks_mask[1] ^ (info->
2653 populated_ranks_mask[1] >> 2)) &
2654 1)
2655 span = 18;
2656 }
2657 if ((info->populated_ranks_mask[0] & 5) == 5) {
2658 central_weight = 20;
2659 side_weight = 20;
2660 }
2661 if (info->clock_speed_index >= 2
2662 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2663 if (info->silicon_revision == 1) {
2664 switch (channel) {
2665 case 0:
2666 if (lane == 1) {
2667 central_weight = 10;
2668 side_weight = 20;
2669 }
2670 break;
2671 case 1:
2672 if (lane == 6) {
2673 side_weight = 5;
2674 central_weight = 20;
2675 }
2676 break;
2677 }
2678 }
2679 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2680 side_weight = 5;
2681 central_weight = 20;
2682 }
2683 }
2684 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2685 reg_178 += span) {
2686 u8 smallest;
2687 u8 largest;
2688 largest = timings[reg_178][channel][slot][rank][lane].largest;
2689 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2690 if (largest - smallest + 1 >= 5) {
2691 unsigned int weight;
2692 if (reg_178 == center_178)
2693 weight = central_weight;
2694 else
2695 weight = side_weight;
2696 sum += weight * (largest + smallest);
2697 count += weight;
2698 }
2699 }
2700 dump_timings(info);
2701 if (count == 0)
2702 die("Couldn't discover DRAM timings (2)\n");
2703 result = sum / (2 * count);
2704 lower_margin =
2705 result - timings[center_178][channel][slot][rank][lane].smallest;
2706 upper_margin =
2707 timings[center_178][channel][slot][rank][lane].largest - result;
2708 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002709 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002710 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002711 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002712 return result;
2713}
2714
2715#define STANDARD_MIN_MARGIN 5
2716
2717static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2718{
2719 u16 margin[64];
2720 int lane, rank, slot, channel;
2721 u8 reg178;
2722 int count = 0, sum = 0;
2723
2724 for (reg178 = reg178_min[info->clock_speed_index];
2725 reg178 < reg178_max[info->clock_speed_index];
2726 reg178 += reg178_step[info->clock_speed_index]) {
2727 margin[reg178] = -1;
2728 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2729 int curmargin =
2730 timings[reg178][channel][slot][rank][lane].largest -
2731 timings[reg178][channel][slot][rank][lane].
2732 smallest + 1;
2733 if (curmargin < margin[reg178])
2734 margin[reg178] = curmargin;
2735 }
2736 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2737 u16 weight;
2738 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2739 sum += weight * reg178;
2740 count += weight;
2741 }
2742 }
2743 dump_timings(info);
2744 if (count == 0)
2745 die("Couldn't discover DRAM timings (3)\n");
2746
2747 u8 threshold;
2748
2749 for (threshold = 30; threshold >= 5; threshold--) {
2750 int usable_length = 0;
2751 int smallest_fount = 0;
2752 for (reg178 = reg178_min[info->clock_speed_index];
2753 reg178 < reg178_max[info->clock_speed_index];
2754 reg178 += reg178_step[info->clock_speed_index])
2755 if (margin[reg178] >= threshold) {
2756 usable_length +=
2757 reg178_step[info->clock_speed_index];
2758 info->training.reg178_largest =
2759 reg178 -
2760 2 * reg178_step[info->clock_speed_index];
2761
2762 if (!smallest_fount) {
2763 smallest_fount = 1;
2764 info->training.reg178_smallest =
2765 reg178 +
2766 reg178_step[info->
2767 clock_speed_index];
2768 }
2769 }
2770 if (usable_length >= 0x21)
2771 break;
2772 }
2773
2774 return sum / count;
2775}
2776
2777static int check_cached_sanity(struct raminfo *info)
2778{
2779 int lane;
2780 int slot, rank;
2781 int channel;
2782
2783 if (!info->cached_training)
2784 return 0;
2785
2786 for (channel = 0; channel < NUM_CHANNELS; channel++)
2787 for (slot = 0; slot < NUM_SLOTS; slot++)
2788 for (rank = 0; rank < NUM_RANKS; rank++)
2789 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2790 u16 cached_value, estimation_value;
2791 cached_value =
2792 info->cached_training->
2793 lane_timings[1][channel][slot][rank]
2794 [lane];
2795 if (cached_value >= 0x18
2796 && cached_value <= 0x1E7) {
2797 estimation_value =
2798 info->training.
2799 lane_timings[1][channel]
2800 [slot][rank][lane];
2801 if (estimation_value <
2802 cached_value - 24)
2803 return 0;
2804 if (estimation_value >
2805 cached_value + 24)
2806 return 0;
2807 }
2808 }
2809 return 1;
2810}
2811
2812static int try_cached_training(struct raminfo *info)
2813{
2814 u8 saved_243[2];
2815 u8 tm;
2816
2817 int channel, slot, rank, lane;
2818 int flip = 1;
2819 int i, j;
2820
2821 if (!check_cached_sanity(info))
2822 return 0;
2823
2824 info->training.reg178_center = info->cached_training->reg178_center;
2825 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2826 info->training.reg178_largest = info->cached_training->reg178_largest;
2827 memcpy(&info->training.timing_bounds,
2828 &info->cached_training->timing_bounds,
2829 sizeof(info->training.timing_bounds));
2830 memcpy(&info->training.timing_offset,
2831 &info->cached_training->timing_offset,
2832 sizeof(info->training.timing_offset));
2833
2834 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002835 saved_243[0] = MCHBAR8(0x243);
2836 saved_243[1] = MCHBAR8(0x643);
2837 MCHBAR8(0x243) = saved_243[0] | 2;
2838 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002839 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002840 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002841 if (read_1d0(0x10b, 6) & 1)
2842 set_10b(info, 0);
2843 for (tm = 0; tm < 2; tm++) {
2844 int totalrank;
2845
2846 set_178(tm ? info->cached_training->reg178_largest : info->
2847 cached_training->reg178_smallest);
2848
2849 totalrank = 0;
2850 /* Check timing ranges. With i == 0 we check smallest one and with
2851 i == 1 the largest bound. With j == 0 we check that on the bound
2852 it still works whereas with j == 1 we check that just outside of
2853 bound we fail.
2854 */
2855 FOR_POPULATED_RANKS_BACKWARDS {
2856 for (i = 0; i < 2; i++) {
2857 for (lane = 0; lane < 8; lane++) {
2858 write_500(info, channel,
2859 info->cached_training->
2860 timing2_bounds[channel][slot]
2861 [rank][lane][i],
2862 get_timing_register_addr(lane,
2863 3,
2864 slot,
2865 rank),
2866 9, 1);
2867
2868 if (!i)
2869 write_500(info, channel,
2870 info->
2871 cached_training->
2872 timing2_offset
2873 [channel][slot][rank]
2874 [lane],
2875 get_timing_register_addr
2876 (lane, 2, slot, rank),
2877 9, 1);
2878 write_500(info, channel,
2879 i ? info->cached_training->
2880 timing_bounds[tm][channel]
2881 [slot][rank][lane].
2882 largest : info->
2883 cached_training->
2884 timing_bounds[tm][channel]
2885 [slot][rank][lane].smallest,
2886 get_timing_register_addr(lane,
2887 0,
2888 slot,
2889 rank),
2890 9, 1);
2891 write_500(info, channel,
2892 info->cached_training->
2893 timing_offset[channel][slot]
2894 [rank][lane] +
2895 (i ? info->cached_training->
2896 timing_bounds[tm][channel]
2897 [slot][rank][lane].
2898 largest : info->
2899 cached_training->
2900 timing_bounds[tm][channel]
2901 [slot][rank][lane].
2902 smallest) - 64,
2903 get_timing_register_addr(lane,
2904 1,
2905 slot,
2906 rank),
2907 9, 1);
2908 }
2909 for (j = 0; j < 2; j++) {
2910 u8 failmask;
2911 u8 expected_failmask;
2912 char reg1b3;
2913
2914 reg1b3 = (j == 1) + 4;
2915 reg1b3 =
2916 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2917 write_1d0(reg1b3, 0x1bb, 6, 1);
2918 write_1d0(reg1b3, 0x1b3, 6, 1);
2919 write_1d0(reg1b3, 0x1a3, 6, 1);
2920
2921 flip = !flip;
2922 write_testing(info, totalrank, flip);
2923 failmask =
2924 check_testing(info, totalrank,
2925 flip);
2926 expected_failmask =
2927 j == 0 ? 0x00 : 0xff;
2928 if (failmask != expected_failmask)
2929 goto fail;
2930 }
2931 }
2932 totalrank++;
2933 }
2934 }
2935
2936 set_178(info->cached_training->reg178_center);
2937 if (info->use_ecc)
2938 set_ecc(1);
2939 write_training_data(info);
2940 write_1d0(0, 322, 3, 1);
2941 info->training = *info->cached_training;
2942
2943 write_1d0(0, 0x1bb, 6, 1);
2944 write_1d0(0, 0x1b3, 6, 1);
2945 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002946 MCHBAR8(0x243) = saved_243[0];
2947 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002948
2949 return 1;
2950
2951fail:
2952 FOR_POPULATED_RANKS {
2953 write_500_timings_type(info, channel, slot, rank, 1);
2954 write_500_timings_type(info, channel, slot, rank, 2);
2955 write_500_timings_type(info, channel, slot, rank, 3);
2956 }
2957
2958 write_1d0(0, 0x1bb, 6, 1);
2959 write_1d0(0, 0x1b3, 6, 1);
2960 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002961 MCHBAR8(0x243) = saved_243[0];
2962 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002963
2964 return 0;
2965}
2966
2967static void do_ram_training(struct raminfo *info)
2968{
2969 u8 saved_243[2];
2970 int totalrank = 0;
2971 u8 reg_178;
2972 int niter;
2973
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002974 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002975 int lane, rank, slot, channel;
2976 u8 reg178_center;
2977
2978 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002979 saved_243[0] = MCHBAR8(0x243);
2980 saved_243[1] = MCHBAR8(0x643);
2981 MCHBAR8(0x243) = saved_243[0] | 2;
2982 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002983 switch (info->clock_speed_index) {
2984 case 0:
2985 niter = 5;
2986 break;
2987 case 1:
2988 niter = 10;
2989 break;
2990 default:
2991 niter = 19;
2992 break;
2993 }
2994 set_ecc(0);
2995
2996 FOR_POPULATED_RANKS_BACKWARDS {
2997 int i;
2998
2999 write_500_timings_type(info, channel, slot, rank, 0);
3000
3001 write_testing(info, totalrank, 0);
3002 for (i = 0; i < niter; i++) {
3003 write_testing_type2(info, totalrank, 2, i, 0);
3004 write_testing_type2(info, totalrank, 3, i, 1);
3005 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003006 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003007 totalrank++;
3008 }
3009
3010 if (reg178_min[info->clock_speed_index] <
3011 reg178_max[info->clock_speed_index])
3012 memset(timings[reg178_min[info->clock_speed_index]], 0,
3013 sizeof(timings[0]) *
3014 (reg178_max[info->clock_speed_index] -
3015 reg178_min[info->clock_speed_index]));
3016 for (reg_178 = reg178_min[info->clock_speed_index];
3017 reg_178 < reg178_max[info->clock_speed_index];
3018 reg_178 += reg178_step[info->clock_speed_index]) {
3019 totalrank = 0;
3020 set_178(reg_178);
3021 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3022 for (slot = 0; slot < NUM_SLOTS; slot++)
3023 for (rank = 0; rank < NUM_RANKS; rank++) {
3024 memset(&timings[reg_178][channel][slot]
3025 [rank][0].smallest, 0, 16);
3026 if (info->
3027 populated_ranks[channel][slot]
3028 [rank]) {
3029 train_ram_at_178(info, channel,
3030 slot, rank,
3031 totalrank,
3032 reg_178, 1,
3033 niter,
3034 timings);
3035 totalrank++;
3036 }
3037 }
3038 }
3039
3040 reg178_center = choose_reg178(info, timings);
3041
3042 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3043 info->training.timing_bounds[0][channel][slot][rank][lane].
3044 smallest =
3045 timings[info->training.
3046 reg178_smallest][channel][slot][rank][lane].
3047 smallest;
3048 info->training.timing_bounds[0][channel][slot][rank][lane].
3049 largest =
3050 timings[info->training.
3051 reg178_smallest][channel][slot][rank][lane].largest;
3052 info->training.timing_bounds[1][channel][slot][rank][lane].
3053 smallest =
3054 timings[info->training.
3055 reg178_largest][channel][slot][rank][lane].smallest;
3056 info->training.timing_bounds[1][channel][slot][rank][lane].
3057 largest =
3058 timings[info->training.
3059 reg178_largest][channel][slot][rank][lane].largest;
3060 info->training.timing_offset[channel][slot][rank][lane] =
3061 info->training.lane_timings[1][channel][slot][rank][lane]
3062 -
3063 info->training.lane_timings[0][channel][slot][rank][lane] +
3064 64;
3065 }
3066
3067 if (info->silicon_revision == 1
3068 && (info->
3069 populated_ranks_mask[1] ^ (info->
3070 populated_ranks_mask[1] >> 2)) & 1) {
3071 int ranks_after_channel1;
3072
3073 totalrank = 0;
3074 for (reg_178 = reg178_center - 18;
3075 reg_178 <= reg178_center + 18; reg_178 += 18) {
3076 totalrank = 0;
3077 set_178(reg_178);
3078 for (slot = 0; slot < NUM_SLOTS; slot++)
3079 for (rank = 0; rank < NUM_RANKS; rank++) {
3080 if (info->
3081 populated_ranks[1][slot][rank]) {
3082 train_ram_at_178(info, 1, slot,
3083 rank,
3084 totalrank,
3085 reg_178, 0,
3086 niter,
3087 timings);
3088 totalrank++;
3089 }
3090 }
3091 }
3092 ranks_after_channel1 = totalrank;
3093
3094 for (reg_178 = reg178_center - 12;
3095 reg_178 <= reg178_center + 12; reg_178 += 12) {
3096 totalrank = ranks_after_channel1;
3097 set_178(reg_178);
3098 for (slot = 0; slot < NUM_SLOTS; slot++)
3099 for (rank = 0; rank < NUM_RANKS; rank++)
3100 if (info->
3101 populated_ranks[0][slot][rank]) {
3102 train_ram_at_178(info, 0, slot,
3103 rank,
3104 totalrank,
3105 reg_178, 0,
3106 niter,
3107 timings);
3108 totalrank++;
3109 }
3110
3111 }
3112 } else {
3113 for (reg_178 = reg178_center - 12;
3114 reg_178 <= reg178_center + 12; reg_178 += 12) {
3115 totalrank = 0;
3116 set_178(reg_178);
3117 FOR_POPULATED_RANKS_BACKWARDS {
3118 train_ram_at_178(info, channel, slot, rank,
3119 totalrank, reg_178, 0, niter,
3120 timings);
3121 totalrank++;
3122 }
3123 }
3124 }
3125
3126 set_178(reg178_center);
3127 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3128 u16 tm0;
3129
3130 tm0 =
3131 choose_training(info, channel, slot, rank, lane, timings,
3132 reg178_center);
3133 write_500(info, channel, tm0,
3134 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3135 write_500(info, channel,
3136 tm0 +
3137 info->training.
3138 lane_timings[1][channel][slot][rank][lane] -
3139 info->training.
3140 lane_timings[0][channel][slot][rank][lane],
3141 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3142 }
3143
3144 totalrank = 0;
3145 FOR_POPULATED_RANKS_BACKWARDS {
3146 try_timing_offsets(info, channel, slot, rank, totalrank);
3147 totalrank++;
3148 }
Felix Held04be2dd2018-07-29 04:53:22 +02003149 MCHBAR8(0x243) = saved_243[0];
3150 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003151 write_1d0(0, 0x142, 3, 1);
3152 info->training.reg178_center = reg178_center;
3153}
3154
3155static void ram_training(struct raminfo *info)
3156{
3157 u16 saved_fc4;
3158
Felix Held04be2dd2018-07-29 04:53:22 +02003159 saved_fc4 = MCHBAR16(0xfc4);
3160 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003161
3162 if (info->revision >= 8)
3163 read_4090(info);
3164
3165 if (!try_cached_training(info))
3166 do_ram_training(info);
3167 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3168 && info->clock_speed_index < 2)
3169 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003170 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003171}
3172
Martin Roth468d02c2019-10-23 21:44:42 -06003173static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003174{
Martin Roth468d02c2019-10-23 21:44:42 -06003175 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003176 if (a > b) {
3177 t = a;
3178 a = b;
3179 b = t;
3180 }
3181 /* invariant a < b. */
3182 while (a) {
3183 t = b % a;
3184 b = a;
3185 a = t;
3186 }
3187 return b;
3188}
3189
3190static inline int div_roundup(int a, int b)
3191{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003192 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003193}
3194
Martin Roth468d02c2019-10-23 21:44:42 -06003195static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003196{
3197 return (a * b) / gcd(a, b);
3198}
3199
3200struct stru1 {
3201 u8 freqs_reversed;
3202 u8 freq_diff_reduced;
3203 u8 freq_min_reduced;
3204 u8 divisor_f4_to_fmax;
3205 u8 divisor_f3_to_fmax;
3206 u8 freq4_to_max_remainder;
3207 u8 freq3_to_2_remainder;
3208 u8 freq3_to_2_remaindera;
3209 u8 freq4_to_2_remainder;
3210 int divisor_f3_to_f1, divisor_f4_to_f2;
3211 int common_time_unit_ps;
3212 int freq_max_reduced;
3213};
3214
3215static void
3216compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3217 int num_cycles_2, int num_cycles_1, int round_it,
3218 int add_freqs, struct stru1 *result)
3219{
3220 int g;
3221 int common_time_unit_ps;
3222 int freq1_reduced, freq2_reduced;
3223 int freq_min_reduced;
3224 int freq_max_reduced;
3225 int freq3, freq4;
3226
3227 g = gcd(freq1, freq2);
3228 freq1_reduced = freq1 / g;
3229 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003230 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3231 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003232
3233 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3234 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3235 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3236 if (add_freqs) {
3237 freq3 += freq2_reduced;
3238 freq4 += freq1_reduced;
3239 }
3240
3241 if (round_it) {
3242 result->freq3_to_2_remainder = 0;
3243 result->freq3_to_2_remaindera = 0;
3244 result->freq4_to_max_remainder = 0;
3245 result->divisor_f4_to_f2 = 0;
3246 result->divisor_f3_to_f1 = 0;
3247 } else {
3248 if (freq2_reduced < freq1_reduced) {
3249 result->freq3_to_2_remainder =
3250 result->freq3_to_2_remaindera =
3251 freq3 % freq1_reduced - freq1_reduced + 1;
3252 result->freq4_to_max_remainder =
3253 -(freq4 % freq1_reduced);
3254 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3255 result->divisor_f4_to_f2 =
3256 (freq4 -
3257 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3258 result->freq4_to_2_remainder =
3259 -(char)((freq1_reduced - freq2_reduced) +
3260 ((u8) freq4 -
3261 (freq1_reduced -
3262 freq2_reduced)) % (u8) freq2_reduced);
3263 } else {
3264 if (freq2_reduced > freq1_reduced) {
3265 result->freq4_to_max_remainder =
3266 (freq4 % freq2_reduced) - freq2_reduced + 1;
3267 result->freq4_to_2_remainder =
3268 freq4 % freq_max_reduced -
3269 freq_max_reduced + 1;
3270 } else {
3271 result->freq4_to_max_remainder =
3272 -(freq4 % freq2_reduced);
3273 result->freq4_to_2_remainder =
3274 -(char)(freq4 % freq_max_reduced);
3275 }
3276 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3277 result->divisor_f3_to_f1 =
3278 (freq3 -
3279 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3280 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3281 result->freq3_to_2_remaindera =
3282 -(char)((freq_max_reduced - freq_min_reduced) +
3283 (freq3 -
3284 (freq_max_reduced -
3285 freq_min_reduced)) % freq1_reduced);
3286 }
3287 }
3288 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3289 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3290 if (round_it) {
3291 if (freq2_reduced > freq1_reduced) {
3292 if (freq3 % freq_max_reduced)
3293 result->divisor_f3_to_fmax++;
3294 }
3295 if (freq2_reduced < freq1_reduced) {
3296 if (freq4 % freq_max_reduced)
3297 result->divisor_f4_to_fmax++;
3298 }
3299 }
3300 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3301 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3302 result->freq_min_reduced = freq_min_reduced;
3303 result->common_time_unit_ps = common_time_unit_ps;
3304 result->freq_max_reduced = freq_max_reduced;
3305}
3306
3307static void
3308set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3309 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3310 int num_cycles_4, int reverse)
3311{
3312 struct stru1 vv;
3313 char multiplier;
3314
3315 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3316 0, 1, &vv);
3317
3318 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003319 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003320 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3321 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3322 div_roundup(num_cycles_1,
3323 vv.common_time_unit_ps) +
3324 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3325 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3326
3327 u32 y =
3328 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3329 vv.freq_max_reduced * multiplier)
3330 | (vv.
3331 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3332 multiplier) << 16) | ((u8) (vv.
3333 freq_min_reduced
3334 *
3335 multiplier)
3336 << 24);
3337 u32 x =
3338 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3339 divisor_f3_to_f1
3340 << 16)
3341 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3342 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003343 MCHBAR32(reg) = y;
3344 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003345 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003346 MCHBAR32(reg + 4) = y;
3347 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003348 }
3349}
3350
3351static void
3352set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3353 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3354 int num_cycles_4)
3355{
3356 struct stru1 ratios1;
3357 struct stru1 ratios2;
3358
3359 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3360 0, 1, &ratios2);
3361 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3362 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003363 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003364 ratios1.freq4_to_max_remainder | (ratios2.
3365 freq4_to_max_remainder
3366 << 8)
3367 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3368 divisor_f4_to_fmax
3369 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003370 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3371 (ratios2.freq4_to_max_remainder << 8) |
3372 (ratios1.divisor_f4_to_fmax << 16) |
3373 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003374}
3375
3376static void
3377set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3378 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3379{
3380 struct stru1 ratios;
3381
3382 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3383 round_it, add_freqs, &ratios);
3384 switch (mode) {
3385 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003386 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3387 (ratios.freqs_reversed << 8);
3388 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3389 (ratios.freq4_to_max_remainder << 8) |
3390 (ratios.divisor_f3_to_fmax << 16) |
3391 (ratios.divisor_f4_to_fmax << 20) |
3392 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003393 break;
3394
3395 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003396 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3397 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003398 break;
3399
3400 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003401 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3402 (ratios.freq4_to_max_remainder << 8) |
3403 (ratios.divisor_f3_to_fmax << 16) |
3404 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003405 break;
3406
3407 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003408 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3409 (ratios.divisor_f4_to_fmax << 8) |
3410 (ratios.freqs_reversed << 12) |
3411 (ratios.freq_min_reduced << 16) |
3412 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003413 break;
3414 }
3415}
3416
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003417static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003418{
3419 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3420 0, 1);
3421 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3422 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3423 1);
3424 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3425 frequency_11(info), 1231, 1524, 0, 1);
3426 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3427 frequency_11(info) / 2, 1278, 2008, 0, 1);
3428 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3429 1167, 1539, 0, 1);
3430 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3431 frequency_11(info) / 2, 1403, 1318, 0, 1);
3432 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3433 1);
3434 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3435 1);
3436 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3437 1, 1);
3438 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3439 1);
3440 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3441 frequency_11(info) / 2, 4000, 0, 0, 0);
3442 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3443 frequency_11(info) / 2, 4000, 4000, 0, 0);
3444
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003445 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003446 printk(RAM_SPEW, "[6dc] <= %x\n",
3447 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003448 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003449 } else
3450 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3451 info->delay46_ps[0], 0,
3452 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003453 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3454 frequency_11(info), 2500, 0, 0, 0);
3455 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3456 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003457 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003458 printk(RAM_SPEW, "[6e8] <= %x\n",
3459 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003460 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003461 } else
3462 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3463 info->delay46_ps[1], 0,
3464 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003465 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3466 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3467 470, 0);
3468 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3469 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3470 454, 459, 0);
3471 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3472 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3473 2588, 0);
3474 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3475 2405, 0);
3476 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3477 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3478 480, 0);
3479 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003480 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3481 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003482}
3483
3484static u16 get_max_timing(struct raminfo *info, int channel)
3485{
3486 int slot, rank, lane;
3487 u16 ret = 0;
3488
Felix Held04be2dd2018-07-29 04:53:22 +02003489 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003490 return 384;
3491
3492 if (info->revision < 8)
3493 return 256;
3494
3495 for (slot = 0; slot < NUM_SLOTS; slot++)
3496 for (rank = 0; rank < NUM_RANKS; rank++)
3497 if (info->populated_ranks[channel][slot][rank])
3498 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003499 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003500 get_timing_register_addr
3501 (lane, 0, slot,
3502 rank), 9));
3503 return ret;
3504}
3505
3506static void set_274265(struct raminfo *info)
3507{
3508 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3509 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3510 int delay_e_over_cycle_ps;
3511 int cycletime_ps;
3512 int channel;
3513
3514 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003515 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3517 cycletime_ps =
3518 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3519 delay_d_ps =
3520 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3521 - info->some_delay_3_ps_rounded + 200;
3522 if (!
3523 ((info->silicon_revision == 0
3524 || info->silicon_revision == 1)
3525 && (info->revision >= 8)))
3526 delay_d_ps += halfcycle_ps(info) * 2;
3527 delay_d_ps +=
3528 halfcycle_ps(info) * (!info->revision_flag_1 +
3529 info->some_delay_2_halfcycles_ceil +
3530 2 * info->some_delay_1_cycle_floor +
3531 info->clock_speed_index +
3532 2 * info->cas_latency - 7 + 11);
3533 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3534
Felix Held04be2dd2018-07-29 04:53:22 +02003535 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3536 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3537 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003538 delay_d_ps += 650;
3539 delay_c_ps = delay_d_ps + 1800;
3540 if (delay_c_ps <= delay_a_ps)
3541 delay_e_ps = 0;
3542 else
3543 delay_e_ps =
3544 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3545 cycletime_ps);
3546
3547 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3548 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3549 delay_f_cycles =
3550 div_roundup(2500 - delay_e_over_cycle_ps,
3551 2 * halfcycle_ps(info));
3552 if (delay_f_cycles > delay_e_cycles) {
3553 info->delay46_ps[channel] = delay_e_ps;
3554 delay_e_cycles = 0;
3555 } else {
3556 info->delay46_ps[channel] =
3557 delay_e_over_cycle_ps +
3558 2 * halfcycle_ps(info) * delay_f_cycles;
3559 delay_e_cycles -= delay_f_cycles;
3560 }
3561
3562 if (info->delay46_ps[channel] < 2500) {
3563 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003564 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003565 }
3566 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3567 if (delay_b_ps <= delay_a_ps)
3568 delay_b_ps = 0;
3569 else
3570 delay_b_ps -= delay_a_ps;
3571 info->delay54_ps[channel] =
3572 cycletime_ps * div_roundup(delay_b_ps,
3573 cycletime_ps) -
3574 2 * halfcycle_ps(info) * delay_e_cycles;
3575 if (info->delay54_ps[channel] < 2500)
3576 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003577 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003578 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3579 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003580 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003581 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003582 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003583 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3584 4 * halfcycle_ps(info)) - 6;
3585 MCHBAR32((channel << 10) + 0x274) =
3586 info->training.reg274265[channel][1] |
3587 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003588 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003589 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3590 4 * halfcycle_ps(info)) + 1;
3591 MCHBAR16((channel << 10) + 0x265) =
3592 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003593 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003594 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003595 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003596 else
Felix Held04be2dd2018-07-29 04:53:22 +02003597 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598}
3599
3600static void restore_274265(struct raminfo *info)
3601{
3602 int channel;
3603
3604 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003605 MCHBAR32((channel << 10) + 0x274) =
3606 (info->cached_training->reg274265[channel][0] << 16) |
3607 info->cached_training->reg274265[channel][1];
3608 MCHBAR16((channel << 10) + 0x265) =
3609 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003611 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003612 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613 else
Felix Held04be2dd2018-07-29 04:53:22 +02003614 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615}
3616
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617static void dmi_setup(void)
3618{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003619 gav(read8(DEFAULT_DMIBAR + 0x254));
3620 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3621 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003622 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003624 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625
3626 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3627 DEFAULT_GPIOBASE | 0x38);
3628 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3629}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003631void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003633 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003634 u16 ggc;
3635 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636
Felix Held04be2dd2018-07-29 04:53:22 +02003637 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3639 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003640 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003641 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643
3644 dmi_setup();
3645
Felix Held04be2dd2018-07-29 04:53:22 +02003646 MCHBAR16(0x1170) = 0xa880;
3647 MCHBAR8(0x11c1) = 0x1;
3648 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003649 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003651 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3652 /* 0 for 32MB */
3653 gfxsize = 0;
3654 }
3655
3656 ggc = 0xb00 | ((gfxsize + 5) << 4);
3657
Angel Pons16fe1e02020-07-22 16:12:33 +02003658 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659
3660 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003661 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662
3663 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003665 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003666 MCHBAR16_OR(0x2c30, 0x200);
3667 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003668 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003669 pci_read_config8(GMA, 0x62); // = 0x2
3670 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003671 read8(DEFAULT_RCBA + 0x2318);
3672 write8(DEFAULT_RCBA + 0x2318, 0x47);
3673 read8(DEFAULT_RCBA + 0x2320);
3674 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675 }
3676
Felix Heldf83d80b2018-07-29 05:30:30 +02003677 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003678
Angel Pons16fe1e02020-07-22 16:12:33 +02003679 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003680 gav(read32(DEFAULT_RCBA + 0x3428));
3681 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003682}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003684void raminit(const int s3resume, const u8 *spd_addrmap)
3685{
Martin Roth468d02c2019-10-23 21:44:42 -06003686 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003687 int i;
3688 struct raminfo info;
3689 u8 x2ca8;
3690 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003691 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003692
Felix Held04be2dd2018-07-29 04:53:22 +02003693 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003694
3695 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3696
Angel Pons16fe1e02020-07-22 16:12:33 +02003697 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698
3699 memset(&info, 0x5a, sizeof(info));
3700
3701 info.last_500_command[0] = 0;
3702 info.last_500_command[1] = 0;
3703
3704 info.fsb_frequency = 135 * 2;
3705 info.board_lane_delay[0] = 0x14;
3706 info.board_lane_delay[1] = 0x07;
3707 info.board_lane_delay[2] = 0x07;
3708 info.board_lane_delay[3] = 0x08;
3709 info.board_lane_delay[4] = 0x56;
3710 info.board_lane_delay[5] = 0x04;
3711 info.board_lane_delay[6] = 0x04;
3712 info.board_lane_delay[7] = 0x05;
3713 info.board_lane_delay[8] = 0x10;
3714
3715 info.training.reg_178 = 0;
3716 info.training.reg_10b = 0;
3717
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718 info.memory_reserved_for_heci_mb = 0;
3719
3720 /* before SPD */
3721 timestamp_add_now(101);
3722
Felix Held29a9c072018-07-29 01:34:45 +02003723 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003724 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725
3726 collect_system_info(&info);
3727
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3729
3730 info.use_ecc = 1;
3731 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003732 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003733 int v;
3734 int try;
3735 int addr;
3736 const u8 useful_addresses[] = {
3737 DEVICE_TYPE,
3738 MODULE_TYPE,
3739 DENSITY,
3740 RANKS_AND_DQ,
3741 MEMORY_BUS_WIDTH,
3742 TIMEBASE_DIVIDEND,
3743 TIMEBASE_DIVISOR,
3744 CYCLETIME,
3745 CAS_LATENCIES_LSB,
3746 CAS_LATENCIES_MSB,
3747 CAS_LATENCY_TIME,
3748 0x11, 0x12, 0x13, 0x14, 0x15,
3749 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3750 0x1c, 0x1d,
3751 THERMAL_AND_REFRESH,
3752 0x20,
3753 REFERENCE_RAW_CARD_USED,
3754 RANK1_ADDRESS_MAPPING,
3755 0x75, 0x76, 0x77, 0x78,
3756 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3757 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3758 0x85, 0x86, 0x87, 0x88,
3759 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3760 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3761 0x95
3762 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003763 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764 continue;
3765 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003766 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003767 DEVICE_TYPE);
3768 if (v >= 0)
3769 break;
3770 }
3771 if (v < 0)
3772 continue;
3773 for (addr = 0;
3774 addr <
3775 sizeof(useful_addresses) /
3776 sizeof(useful_addresses[0]); addr++)
3777 gav(info.
3778 spd[channel][0][useful_addresses
3779 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003780 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003781 useful_addresses
3782 [addr]));
3783 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3784 die("Only DDR3 is supported");
3785
3786 v = info.spd[channel][0][RANKS_AND_DQ];
3787 info.populated_ranks[channel][0][0] = 1;
3788 info.populated_ranks[channel][0][1] =
3789 ((v >> 3) & 7);
3790 if (((v >> 3) & 7) > 1)
3791 die("At most 2 ranks are supported");
3792 if ((v & 7) == 0 || (v & 7) > 2)
3793 die("Only x8 and x16 modules are supported");
3794 if ((info.
3795 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3796 && (info.
3797 spd[channel][slot][MODULE_TYPE] & 0xF)
3798 != 3)
3799 die("Registered memory is not supported");
3800 info.is_x16_module[channel][0] = (v & 7) - 1;
3801 info.density[channel][slot] =
3802 info.spd[channel][slot][DENSITY] & 0xF;
3803 if (!
3804 (info.
3805 spd[channel][slot][MEMORY_BUS_WIDTH] &
3806 0x18))
3807 info.use_ecc = 0;
3808 }
3809
3810 gav(0x55);
3811
3812 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3813 int v = 0;
3814 for (slot = 0; slot < NUM_SLOTS; slot++)
3815 for (rank = 0; rank < NUM_RANKS; rank++)
3816 v |= info.
3817 populated_ranks[channel][slot][rank]
3818 << (2 * slot + rank);
3819 info.populated_ranks_mask[channel] = v;
3820 }
3821
3822 gav(0x55);
3823
Angel Pons16fe1e02020-07-22 16:12:33 +02003824 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003825 }
3826
3827 /* after SPD */
3828 timestamp_add_now(102);
3829
Felix Held04be2dd2018-07-29 04:53:22 +02003830 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003831
3832 collect_system_info(&info);
3833 calculate_timings(&info);
3834
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003836 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837 if (x2ca8 == 0 && (reg8 & 0x80)) {
3838 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3839 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3840 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3841 */
3842
3843 /* Clear bit7. */
3844
3845 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3846 (reg8 & ~(1 << 7)));
3847
3848 printk(BIOS_INFO,
3849 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003850 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851 }
3852 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003853
3854 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003855 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3856 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003857
3858 compute_derived_timings(&info);
3859
3860 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003861 gav(MCHBAR8(0x164));
3862 MCHBAR8(0x164) = 0x26;
3863 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003864 }
3865
Felix Held04be2dd2018-07-29 04:53:22 +02003866 MCHBAR32_OR(0x18b4, 0x210000);
3867 MCHBAR32_OR(0x1890, 0x2000000);
3868 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869
Angel Ponsa457e352020-07-22 18:17:33 +02003870 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3871 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872
Felix Held04be2dd2018-07-29 04:53:22 +02003873 gav(MCHBAR16(0x2c10));
3874 MCHBAR16(0x2c10) = 0x412;
3875 gav(MCHBAR16(0x2c10));
3876 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003877
Felix Held04be2dd2018-07-29 04:53:22 +02003878 gav(MCHBAR8(0x2ca8)); // !!!!
3879 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880
Angel Ponsa457e352020-07-22 18:17:33 +02003881 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3882 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003883 gav(MCHBAR32(0x1c04)); // !!!!
3884 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003885
3886 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003887 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003888 }
3889
Felix Held04be2dd2018-07-29 04:53:22 +02003890 MCHBAR32(0x18d8) = 0x120000;
3891 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003892 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3893 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003894 MCHBAR32(0x18d8) = 0x40000;
3895 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003896 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3897 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003898 MCHBAR32(0x18d8) = 0x180000;
3899 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003900 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3901 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003902 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003903
Felix Held04be2dd2018-07-29 04:53:22 +02003904 gav(MCHBAR32(0x18dc)); // !!!!
3905 MCHBAR32(0x18dc) = 0x3;
3906 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003907
3908 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003909 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910 }
3911
Felix Held04be2dd2018-07-29 04:53:22 +02003912 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003913 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32(0x1a10) = 0x4200010e;
3915 MCHBAR32_OR(0x18b8, 0x200);
3916 gav(MCHBAR32(0x1918)); // !!!!
3917 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003918
Felix Held04be2dd2018-07-29 04:53:22 +02003919 gav(MCHBAR32(0x18b8)); // !!!!
3920 MCHBAR32(0x18b8) = 0xe00;
3921 gav(MCHBAR32(0x182c)); // !!!!
3922 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003923 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3924 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003925 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3926 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
Felix Held04be2dd2018-07-29 04:53:22 +02003928 MCHBAR32_AND(0x18b4, 0xffff7fff);
3929 gav(MCHBAR32(0x1a68)); // !!!!
3930 MCHBAR32(0x1a68) = 0x343800;
3931 gav(MCHBAR32(0x1e68)); // !!!!
3932 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003933
3934 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003935 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003936 }
3937
Angel Pons08143572020-07-22 17:47:06 +02003938 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3939 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3940 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3941 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3942 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003943 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3944 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003945 gav(MCHBAR32(0x1af0)); // !!!!
3946 gav(MCHBAR32(0x1af0)); // !!!!
3947 MCHBAR32(0x1af0) = 0x1f020003;
3948 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003949
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003950 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952 }
3953
Felix Held04be2dd2018-07-29 04:53:22 +02003954 gav(MCHBAR32(0x1890)); // !!!!
3955 MCHBAR32(0x1890) = 0x80102;
3956 gav(MCHBAR32(0x18b4)); // !!!!
3957 MCHBAR32(0x18b4) = 0x216000;
3958 MCHBAR32(0x18a4) = 0x22222222;
3959 MCHBAR32(0x18a8) = 0x22222222;
3960 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003961
3962 udelay(1000);
3963
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003964 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003965
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003966 if (x2ca8 == 0) {
3967 int j;
3968 if (s3resume && info.cached_training) {
3969 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003970 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003971 info.cached_training->reg2ca9_bit0);
3972 for (i = 0; i < 2; i++)
3973 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003974 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003975 i, j, info.cached_training->reg274265[i][j]);
3976 } else {
3977 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003978 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003979 info.training.reg2ca9_bit0);
3980 for (i = 0; i < 2; i++)
3981 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003982 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003983 i, j, info.training.reg274265[i][j]);
3984 }
3985
3986 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003987
3988 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003989 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003990 }
3991
3992 udelay(1000);
3993
3994 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003995 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003996 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003997 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3998 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3999 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004000
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004001 MCHBAR8(0x1150);
4002 MCHBAR8(0x1151);
4003 MCHBAR8(0x1022);
4004 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004005 MCHBAR32(0x1300) = 0x60606060;
4006 MCHBAR32(0x1304) = 0x60606060;
4007 MCHBAR32(0x1308) = 0x78797a7b;
4008 MCHBAR32(0x130c) = 0x7c7d7e7f;
4009 MCHBAR32(0x1310) = 0x60606060;
4010 MCHBAR32(0x1314) = 0x60606060;
4011 MCHBAR32(0x1318) = 0x60606060;
4012 MCHBAR32(0x131c) = 0x60606060;
4013 MCHBAR32(0x1320) = 0x50515253;
4014 MCHBAR32(0x1324) = 0x54555657;
4015 MCHBAR32(0x1328) = 0x58595a5b;
4016 MCHBAR32(0x132c) = 0x5c5d5e5f;
4017 MCHBAR32(0x1330) = 0x40414243;
4018 MCHBAR32(0x1334) = 0x44454647;
4019 MCHBAR32(0x1338) = 0x48494a4b;
4020 MCHBAR32(0x133c) = 0x4c4d4e4f;
4021 MCHBAR32(0x1340) = 0x30313233;
4022 MCHBAR32(0x1344) = 0x34353637;
4023 MCHBAR32(0x1348) = 0x38393a3b;
4024 MCHBAR32(0x134c) = 0x3c3d3e3f;
4025 MCHBAR32(0x1350) = 0x20212223;
4026 MCHBAR32(0x1354) = 0x24252627;
4027 MCHBAR32(0x1358) = 0x28292a2b;
4028 MCHBAR32(0x135c) = 0x2c2d2e2f;
4029 MCHBAR32(0x1360) = 0x10111213;
4030 MCHBAR32(0x1364) = 0x14151617;
4031 MCHBAR32(0x1368) = 0x18191a1b;
4032 MCHBAR32(0x136c) = 0x1c1d1e1f;
4033 MCHBAR32(0x1370) = 0x10203;
4034 MCHBAR32(0x1374) = 0x4050607;
4035 MCHBAR32(0x1378) = 0x8090a0b;
4036 MCHBAR32(0x137c) = 0xc0d0e0f;
4037 MCHBAR8(0x11cc) = 0x4e;
4038 MCHBAR32(0x1110) = 0x73970404;
4039 MCHBAR32(0x1114) = 0x72960404;
4040 MCHBAR32(0x1118) = 0x6f950404;
4041 MCHBAR32(0x111c) = 0x6d940404;
4042 MCHBAR32(0x1120) = 0x6a930404;
4043 MCHBAR32(0x1124) = 0x68a41404;
4044 MCHBAR32(0x1128) = 0x66a21404;
4045 MCHBAR32(0x112c) = 0x63a01404;
4046 MCHBAR32(0x1130) = 0x609e1404;
4047 MCHBAR32(0x1134) = 0x5f9c1404;
4048 MCHBAR32(0x1138) = 0x5c961404;
4049 MCHBAR32(0x113c) = 0x58a02404;
4050 MCHBAR32(0x1140) = 0x54942404;
4051 MCHBAR32(0x1190) = 0x900080a;
4052 MCHBAR16(0x11c0) = 0xc40b;
4053 MCHBAR16(0x11c2) = 0x303;
4054 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004055 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004056 MCHBAR32(0x11b8) = 0x70c3000;
4057 MCHBAR8(0x11ec) = 0xa;
4058 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004059 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004060 MCHBAR16(0x11ca) = 0xfa;
4061 MCHBAR32(0x11e4) = 0x4e20;
4062 MCHBAR8(0x11bc) = 0xf;
4063 MCHBAR16(0x11da) = 0x19;
4064 MCHBAR16(0x11ba) = 0x470c;
4065 MCHBAR32(0x1680) = 0xe6ffe4ff;
4066 MCHBAR32(0x1684) = 0xdeffdaff;
4067 MCHBAR32(0x1688) = 0xd4ffd0ff;
4068 MCHBAR32(0x168c) = 0xccffc6ff;
4069 MCHBAR32(0x1690) = 0xc0ffbeff;
4070 MCHBAR32(0x1694) = 0xb8ffb0ff;
4071 MCHBAR32(0x1698) = 0xa8ff0000;
4072 MCHBAR32(0x169c) = 0xc00;
4073 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004074 }
4075
Felix Held04be2dd2018-07-29 04:53:22 +02004076 MCHBAR32(0x124c) = 0x15040d00;
4077 MCHBAR32(0x1250) = 0x7f0000;
4078 MCHBAR32(0x1254) = 0x1e220004;
4079 MCHBAR32(0x1258) = 0x4000004;
4080 MCHBAR32(0x1278) = 0x0;
4081 MCHBAR32(0x125c) = 0x0;
4082 MCHBAR32(0x1260) = 0x0;
4083 MCHBAR32(0x1264) = 0x0;
4084 MCHBAR32(0x1268) = 0x0;
4085 MCHBAR32(0x126c) = 0x0;
4086 MCHBAR32(0x1270) = 0x0;
4087 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004088 }
4089
4090 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004091 MCHBAR16(0x1214) = 0x320;
4092 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004093 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4094 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004095 MCHBAR32(0x1400) = 0x13040020;
4096 MCHBAR32(0x1404) = 0xe090120;
4097 MCHBAR32(0x1408) = 0x5120220;
4098 MCHBAR32(0x140c) = 0x5120330;
4099 MCHBAR32(0x1410) = 0xe090220;
4100 MCHBAR32(0x1414) = 0x1010001;
4101 MCHBAR32(0x1418) = 0x1110000;
4102 MCHBAR32(0x141c) = 0x9020020;
4103 MCHBAR32(0x1420) = 0xd090220;
4104 MCHBAR32(0x1424) = 0x2090220;
4105 MCHBAR32(0x1428) = 0x2090330;
4106 MCHBAR32(0x142c) = 0xd090220;
4107 MCHBAR32(0x1430) = 0x1010001;
4108 MCHBAR32(0x1434) = 0x1110000;
4109 MCHBAR32(0x1438) = 0x11040020;
4110 MCHBAR32(0x143c) = 0x4030220;
4111 MCHBAR32(0x1440) = 0x1060220;
4112 MCHBAR32(0x1444) = 0x1060330;
4113 MCHBAR32(0x1448) = 0x4030220;
4114 MCHBAR32(0x144c) = 0x1010001;
4115 MCHBAR32(0x1450) = 0x1110000;
4116 MCHBAR32(0x1454) = 0x4010020;
4117 MCHBAR32(0x1458) = 0xb090220;
4118 MCHBAR32(0x145c) = 0x1090220;
4119 MCHBAR32(0x1460) = 0x1090330;
4120 MCHBAR32(0x1464) = 0xb090220;
4121 MCHBAR32(0x1468) = 0x1010001;
4122 MCHBAR32(0x146c) = 0x1110000;
4123 MCHBAR32(0x1470) = 0xf040020;
4124 MCHBAR32(0x1474) = 0xa090220;
4125 MCHBAR32(0x1478) = 0x1120220;
4126 MCHBAR32(0x147c) = 0x1120330;
4127 MCHBAR32(0x1480) = 0xa090220;
4128 MCHBAR32(0x1484) = 0x1010001;
4129 MCHBAR32(0x1488) = 0x1110000;
4130 MCHBAR32(0x148c) = 0x7020020;
4131 MCHBAR32(0x1490) = 0x1010220;
4132 MCHBAR32(0x1494) = 0x10210;
4133 MCHBAR32(0x1498) = 0x10320;
4134 MCHBAR32(0x149c) = 0x1010220;
4135 MCHBAR32(0x14a0) = 0x1010001;
4136 MCHBAR32(0x14a4) = 0x1110000;
4137 MCHBAR32(0x14a8) = 0xd040020;
4138 MCHBAR32(0x14ac) = 0x8090220;
4139 MCHBAR32(0x14b0) = 0x1111310;
4140 MCHBAR32(0x14b4) = 0x1111420;
4141 MCHBAR32(0x14b8) = 0x8090220;
4142 MCHBAR32(0x14bc) = 0x1010001;
4143 MCHBAR32(0x14c0) = 0x1110000;
4144 MCHBAR32(0x14c4) = 0x3010020;
4145 MCHBAR32(0x14c8) = 0x7090220;
4146 MCHBAR32(0x14cc) = 0x1081310;
4147 MCHBAR32(0x14d0) = 0x1081420;
4148 MCHBAR32(0x14d4) = 0x7090220;
4149 MCHBAR32(0x14d8) = 0x1010001;
4150 MCHBAR32(0x14dc) = 0x1110000;
4151 MCHBAR32(0x14e0) = 0xb040020;
4152 MCHBAR32(0x14e4) = 0x2030220;
4153 MCHBAR32(0x14e8) = 0x1051310;
4154 MCHBAR32(0x14ec) = 0x1051420;
4155 MCHBAR32(0x14f0) = 0x2030220;
4156 MCHBAR32(0x14f4) = 0x1010001;
4157 MCHBAR32(0x14f8) = 0x1110000;
4158 MCHBAR32(0x14fc) = 0x5020020;
4159 MCHBAR32(0x1500) = 0x5090220;
4160 MCHBAR32(0x1504) = 0x2071310;
4161 MCHBAR32(0x1508) = 0x2071420;
4162 MCHBAR32(0x150c) = 0x5090220;
4163 MCHBAR32(0x1510) = 0x1010001;
4164 MCHBAR32(0x1514) = 0x1110000;
4165 MCHBAR32(0x1518) = 0x7040120;
4166 MCHBAR32(0x151c) = 0x2090220;
4167 MCHBAR32(0x1520) = 0x70b1210;
4168 MCHBAR32(0x1524) = 0x70b1310;
4169 MCHBAR32(0x1528) = 0x2090220;
4170 MCHBAR32(0x152c) = 0x1010001;
4171 MCHBAR32(0x1530) = 0x1110000;
4172 MCHBAR32(0x1534) = 0x1010110;
4173 MCHBAR32(0x1538) = 0x1081310;
4174 MCHBAR32(0x153c) = 0x5041200;
4175 MCHBAR32(0x1540) = 0x5041310;
4176 MCHBAR32(0x1544) = 0x1081310;
4177 MCHBAR32(0x1548) = 0x1010001;
4178 MCHBAR32(0x154c) = 0x1110000;
4179 MCHBAR32(0x1550) = 0x1040120;
4180 MCHBAR32(0x1554) = 0x4051210;
4181 MCHBAR32(0x1558) = 0xd051200;
4182 MCHBAR32(0x155c) = 0xd051200;
4183 MCHBAR32(0x1560) = 0x4051210;
4184 MCHBAR32(0x1564) = 0x1010001;
4185 MCHBAR32(0x1568) = 0x1110000;
4186 MCHBAR16(0x1222) = 0x220a;
4187 MCHBAR16(0x123c) = 0x1fc0;
4188 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004189 }
4190
Felix Heldf83d80b2018-07-29 05:30:30 +02004191 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004192 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004193 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004194
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004195 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004196
4197 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004198 MCHBAR8_AND(0x2ca8, ~3);
4199 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004200 /* This issues a CPU reset without resetting the platform */
4201 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004202 /* Write back the S3 state to PM1_CNT to let the reset CPU
4203 know it also needs to take the s3 path. */
4204 if (s3resume)
4205 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4206 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004207 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004208 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004209 }
4210
Felix Held04be2dd2018-07-29 04:53:22 +02004211 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004212 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004213 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004214 MCHBAR16(0x2c20); // !!!!
4215 MCHBAR16(0x2c10); // !!!!
4216 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004217 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004218 udelay(1000);
4219 write_1d0(0, 0x33d, 0, 0);
4220 write_500(&info, 0, 0, 0xb61, 0, 0);
4221 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004222 MCHBAR32(0x1a30) = 0x0;
4223 MCHBAR32(0x1a34) = 0x0;
4224 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4225 (info.populated_ranks[0][0][0] * 0xa0);
4226 MCHBAR16(0x616) = 0x26a;
4227 MCHBAR32(0x134) = 0x856000;
4228 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004229 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4230 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004231 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004232 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4233 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004234 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004235 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004236 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4237 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004238 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4239 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4240 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4241 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4242 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4243 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4244 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4245 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4246 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4247 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004248 }
4249
4250 write_1d0(0x4, 0x151, 4, 1);
4251 write_1d0(0, 0x142, 3, 1);
4252 rdmsr(0x1ac); // !!!!
4253 write_500(&info, 1, 1, 0x6b3, 4, 1);
4254 write_500(&info, 1, 1, 0x6cf, 4, 1);
4255
4256 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4257
4258 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4259 populated_ranks[0]
4260 [0][0]) << 0),
4261 0x1d1, 3, 1);
4262 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004263 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4264 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004265 }
4266
4267 set_334(0);
4268
4269 program_base_timings(&info);
4270
Felix Held04be2dd2018-07-29 04:53:22 +02004271 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004272
4273 write_1d0(0x2, 0x1d5, 2, 1);
4274 write_1d0(0x20, 0x166, 7, 1);
4275 write_1d0(0x0, 0xeb, 3, 1);
4276 write_1d0(0x0, 0xf3, 6, 1);
4277
4278 for (channel = 0; channel < NUM_CHANNELS; channel++)
4279 for (lane = 0; lane < 9; lane++) {
4280 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4281 u8 a;
4282 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4283 write_500(&info, channel, a, addr, 6, 1);
4284 }
4285
4286 udelay(1000);
4287
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004288 if (s3resume) {
4289 if (info.cached_training == NULL) {
4290 u32 reg32;
4291 printk(BIOS_ERR,
4292 "Couldn't find training data. Rebooting\n");
4293 reg32 = inl(DEFAULT_PMBASE + 0x04);
4294 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004295 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004296 }
4297 int tm;
4298 info.training = *info.cached_training;
4299 for (tm = 0; tm < 4; tm++)
4300 for (channel = 0; channel < NUM_CHANNELS; channel++)
4301 for (slot = 0; slot < NUM_SLOTS; slot++)
4302 for (rank = 0; rank < NUM_RANKS; rank++)
4303 for (lane = 0; lane < 9; lane++)
4304 write_500(&info,
4305 channel,
4306 info.training.
4307 lane_timings
4308 [tm][channel]
4309 [slot][rank]
4310 [lane],
4311 get_timing_register_addr
4312 (lane, tm,
4313 slot, rank),
4314 9, 0);
4315 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4316 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4317 }
4318
Felix Heldf83d80b2018-07-29 05:30:30 +02004319 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004320 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004321 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004322 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323
4324 program_board_delay(&info);
4325
Felix Held04be2dd2018-07-29 04:53:22 +02004326 MCHBAR8(0x5ff) = 0x0;
4327 MCHBAR8(0x5ff) = 0x80;
4328 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004329
Felix Held04be2dd2018-07-29 04:53:22 +02004330 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004331 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004332 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004333 gav(read_1d0(0x14b, 7)); // = 0x81023100
4334 write_1d0(0x30, 0x14b, 7, 1);
4335 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4336 write_1d0(7, 0xd6, 6, 1);
4337 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4338 write_1d0(7, 0x328, 6, 1);
4339
4340 for (channel = 0; channel < NUM_CHANNELS; channel++)
4341 set_4cf(&info, channel,
4342 info.populated_ranks[channel][0][0] ? 8 : 0);
4343
4344 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4345 write_1d0(2, 0x116, 4, 1);
4346 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4347 write_1d0(0, 0xae, 6, 1);
4348 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4349 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004350 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4351 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004352 MCHBAR32_AND(0x140, ~0x07000000);
4353 MCHBAR32_AND(0x138, ~0x07000000);
4354 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004355 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004356 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004357 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004358
4359 {
4360 u32 t;
4361 u8 val_a1;
4362 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4363 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4364 rmw_1d0(0x320, 0x07,
4365 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4366 rmw_1d0(0x14b, 0x78,
4367 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4368 4), 7,
4369 1);
4370 rmw_1d0(0xce, 0x38,
4371 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4372 4), 6,
4373 1);
4374 }
4375
4376 for (channel = 0; channel < NUM_CHANNELS; channel++)
4377 set_4cf(&info, channel,
4378 info.populated_ranks[channel][0][0] ? 9 : 1);
4379
4380 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004381 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004382 write_1d0(2, 0xae, 6, 1);
4383 write_1d0(2, 0x300, 6, 1);
4384 write_1d0(2, 0x121, 3, 1);
4385 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4386 write_1d0(4, 0xd6, 6, 1);
4387 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4388 write_1d0(4, 0x328, 6, 1);
4389
4390 for (channel = 0; channel < NUM_CHANNELS; channel++)
4391 set_4cf(&info, channel,
4392 info.populated_ranks[channel][0][0] ? 9 : 0);
4393
Felix Held04be2dd2018-07-29 04:53:22 +02004394 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4395 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004396 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004397 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004398 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4399 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4400 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4401 write_1d0(0, 0x21c, 6, 1);
4402 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4403 write_1d0(0x35, 0x14b, 7, 1);
4404
4405 for (channel = 0; channel < NUM_CHANNELS; channel++)
4406 set_4cf(&info, channel,
4407 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4408
4409 set_334(1);
4410
Felix Held04be2dd2018-07-29 04:53:22 +02004411 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004412
4413 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4414 write_500(&info, channel,
4415 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4416 1);
4417 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4418 }
Felix Held04be2dd2018-07-29 04:53:22 +02004419 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4420 MCHBAR16(0x6c0) = 0x14a0;
4421 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4422 MCHBAR16(0x232) = 0x8;
4423 /* 0x40004 or 0 depending on ? */
4424 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4425 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4426 MCHBAR32(0x128) = 0x2150d05;
4427 MCHBAR8(0x12c) = 0x1f;
4428 MCHBAR8(0x12d) = 0x56;
4429 MCHBAR8(0x12e) = 0x31;
4430 MCHBAR8(0x12f) = 0x0;
4431 MCHBAR8(0x271) = 0x2;
4432 MCHBAR8(0x671) = 0x2;
4433 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004434 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004435 MCHBAR32(0x294 + (channel << 10)) =
4436 (info.populated_ranks_mask[channel] & 3) << 16;
4437 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4438 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004439 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004440 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4441 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004442
4443 if (!s3resume)
4444 jedec_init(&info);
4445
4446 int totalrank = 0;
4447 for (channel = 0; channel < NUM_CHANNELS; channel++)
4448 for (slot = 0; slot < NUM_SLOTS; slot++)
4449 for (rank = 0; rank < NUM_RANKS; rank++)
4450 if (info.populated_ranks[channel][slot][rank]) {
4451 jedec_read(&info, channel, slot, rank,
4452 totalrank, 0xa, 0x400);
4453 totalrank++;
4454 }
4455
Felix Held04be2dd2018-07-29 04:53:22 +02004456 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457
Felix Heldf83d80b2018-07-29 05:30:30 +02004458 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4459 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004460
4461 if (!s3resume) {
4462 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004463 MCHBAR32(0x294 + (channel << 10)) =
4464 (info.populated_ranks_mask[channel] & 3) << 16;
4465 MCHBAR16(0x298 + (channel << 10)) =
4466 info.populated_ranks[channel][0][0] |
4467 (info.populated_ranks[channel][0][1] << 5);
4468 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004469 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004470 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004471
4472 {
4473 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004474 a = MCHBAR8(0x243);
4475 b = MCHBAR8(0x643);
4476 MCHBAR8(0x243) = a | 2;
4477 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004478 }
4479
4480 write_1d0(7, 0x19b, 3, 1);
4481 write_1d0(7, 0x1c0, 3, 1);
4482 write_1d0(4, 0x1c6, 4, 1);
4483 write_1d0(4, 0x1cc, 4, 1);
4484 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4485 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004486 MCHBAR32(0x584) = 0xfffff;
4487 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004488
4489 for (channel = 0; channel < NUM_CHANNELS; channel++)
4490 for (slot = 0; slot < NUM_SLOTS; slot++)
4491 for (rank = 0; rank < NUM_RANKS; rank++)
4492 if (info.
4493 populated_ranks[channel][slot]
4494 [rank])
4495 config_rank(&info, s3resume,
4496 channel, slot,
4497 rank);
4498
Felix Held04be2dd2018-07-29 04:53:22 +02004499 MCHBAR8(0x243) = 0x1;
4500 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004501 }
4502
4503 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004504 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505 write_26c(0, 0x820);
4506 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004507 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508 /* end */
4509
4510 if (s3resume) {
4511 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004512 MCHBAR32(0x294 + (channel << 10)) =
4513 (info.populated_ranks_mask[channel] & 3) << 16;
4514 MCHBAR16(0x298 + (channel << 10)) =
4515 info.populated_ranks[channel][0][0] |
4516 (info.populated_ranks[channel][0][1] << 5);
4517 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004518 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004519 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 }
4521
Felix Held04be2dd2018-07-29 04:53:22 +02004522 MCHBAR32_AND(0xfa4, ~0x01000002);
4523 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004525 /* Before training. */
4526 timestamp_add_now(103);
4527
4528 if (!s3resume)
4529 ram_training(&info);
4530
4531 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004532 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533
4534 dump_timings(&info);
4535
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004536 program_modules_memory_map(&info, 0);
4537 program_total_memory_map(&info);
4538
4539 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004540 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004542 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004544 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004545 else
Felix Held04be2dd2018-07-29 04:53:22 +02004546 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547
Felix Held04be2dd2018-07-29 04:53:22 +02004548 MCHBAR32_AND(0xfac, ~0x80000000);
4549 MCHBAR32(0xfb4) = 0x4800;
4550 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4551 MCHBAR32(0xe94) = 0x7ffff;
4552 MCHBAR32(0xfc0) = 0x80002040;
4553 MCHBAR32(0xfc4) = 0x701246;
4554 MCHBAR8_AND(0xfc8, ~0x70);
4555 MCHBAR32_OR(0xe5c, 0x1000000);
4556 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4557 MCHBAR32(0x50) = 0x700b0;
4558 MCHBAR32(0x3c) = 0x10;
4559 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4560 MCHBAR8_OR(0xff4, 0x2);
4561 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004562
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4564 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4565 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004567 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4568 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4569 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 {
4572 u32 eax;
4573
4574 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4576 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4577 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 }
4579
4580 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584 else
Felix Held04be2dd2018-07-29 04:53:22 +02004585 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004588
Felix Held04be2dd2018-07-29 04:53:22 +02004589 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004590 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004591 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592 else
Felix Held04be2dd2018-07-29 04:53:22 +02004593 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594 }
4595
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597
4598 {
4599 u8 al;
4600 al = 0xd;
4601 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4602 al += 2;
4603 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004604 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004605 }
4606
4607 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004608 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4609 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4610 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4611 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004612 }
4613 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004614 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004615 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004616 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004617 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004618 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004619 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004620 MCHBAR8_OR(0x1210, 2);
4621 MCHBAR32(0x1200) = 0x8800440;
4622 MCHBAR32(0x1204) = 0x53ff0453;
4623 MCHBAR32(0x1208) = 0x19002043;
4624 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004625
4626 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004627 MCHBAR16(0x1214) = 0x220;
4628 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004629 }
4630
Felix Held04be2dd2018-07-29 04:53:22 +02004631 MCHBAR8_OR(0x1214, 0x4);
4632 MCHBAR8(0x120c) = 0x1;
4633 MCHBAR8(0x1218) = 0x3;
4634 MCHBAR8(0x121a) = 0x3;
4635 MCHBAR8(0x121c) = 0x3;
4636 MCHBAR16(0xc14) = 0x0;
4637 MCHBAR16(0xc20) = 0x0;
4638 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639
4640 /* revision dependent here. */
4641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
4644 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR16_OR(0x1230, 0x8000);
4648 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649
4650 u8 bl, ebpb;
4651 u16 reg_1020;
4652
Felix Held04be2dd2018-07-29 04:53:22 +02004653 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4654 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004655
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR32(0x1000) = 0x100;
4657 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658
4659 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661 bl = reg_1020 >> 8;
4662 ebpb = reg_1020 & 0xff;
4663 } else {
4664 ebpb = 0;
4665 bl = 8;
4666 }
4667
4668 rdmsr(0x1a2);
4669
Felix Held04be2dd2018-07-29 04:53:22 +02004670 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004671
Felix Held04be2dd2018-07-29 04:53:22 +02004672 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675
Felix Held04be2dd2018-07-29 04:53:22 +02004676 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004678 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4679 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680 }
4681
4682 setup_heci_uma(&info);
4683
4684 if (info.uma_enabled) {
4685 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR32_OR(0x11b0, 0x4000);
4687 MCHBAR32_OR(0x11b4, 0x4000);
4688 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004689
Felix Held04be2dd2018-07-29 04:53:22 +02004690 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4691 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4692 MCHBAR16_OR(0x1170, 0x1000);
4693
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004695
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004696 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004697 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004698 ;
4699 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004700 }
4701
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004702 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4703 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004705 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707 udelay(1000);
4708 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004709 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4710
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711 if (!s3resume)
4712 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004713 if (s3resume && cbmem_wasnot_inited) {
4714 u32 reg32;
4715 printk(BIOS_ERR, "Failed S3 resume.\n");
4716 ram_check(0x100000, 0x200000);
4717
4718 /* Clear SLP_TYPE. */
4719 reg32 = inl(DEFAULT_PMBASE + 0x04);
4720 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4721
4722 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004723 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004724 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725}