blob: ecf8ef857643dc080d05002d94dbf877e991f924 [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
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100333#define NUM_CHANNELS 2
334#define NUM_SLOTS 2
335#define NUM_RANKS 2
336#define RANK_SHIFT 28
337#define CHANNEL_SHIFT 10
338
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100339static void seq9(struct raminfo *info, int channel, int slot, int rank)
340{
341 int i, lane;
342
343 for (i = 0; i < 2; i++)
344 for (lane = 0; lane < 8; lane++)
345 write_500(info, channel,
346 info->training.lane_timings[i +
347 1][channel][slot]
348 [rank][lane], get_timing_register_addr(lane,
349 i + 1,
350 slot,
351 rank),
352 9, 0);
353
354 write_1d0(1, 0x103, 6, 1);
355 for (lane = 0; lane < 8; lane++)
356 write_500(info, channel,
357 info->training.
358 lane_timings[0][channel][slot][rank][lane],
359 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
360
361 for (i = 0; i < 2; i++) {
362 for (lane = 0; lane < 8; lane++)
363 write_500(info, channel,
364 info->training.lane_timings[i +
365 1][channel][slot]
366 [rank][lane], get_timing_register_addr(lane,
367 i + 1,
368 slot,
369 rank),
370 9, 0);
371 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
372 }
373
374 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200375 MCHBAR8(0x5ff) = 0x0;
376 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100377 write_1d0(0x2, 0x142, 3, 1);
378 for (lane = 0; lane < 8; lane++) {
379 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
380 info->training.lane_timings[2][channel][slot][rank][lane] =
381 read_500(info, channel,
382 get_timing_register_addr(lane, 2, slot, rank), 9);
383 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
384 info->training.lane_timings[3][channel][slot][rank][lane] =
385 info->training.lane_timings[2][channel][slot][rank][lane] +
386 0x20;
387 }
388}
389
390static int count_ranks_in_channel(struct raminfo *info, int channel)
391{
392 int slot, rank;
393 int res = 0;
394 for (slot = 0; slot < NUM_SLOTS; slot++)
395 for (rank = 0; rank < NUM_SLOTS; rank++)
396 res += info->populated_ranks[channel][slot][rank];
397 return res;
398}
399
400static void
401config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
402{
403 int add;
404
405 write_1d0(0, 0x178, 7, 1);
406 seq9(info, channel, slot, rank);
407 program_timings(info, 0x80, channel, slot, rank);
408
409 if (channel == 0)
410 add = count_ranks_in_channel(info, 1);
411 else
412 add = 0;
413 if (!s3resume)
414 gav(rw_test(rank + add));
415 program_timings(info, 0x00, channel, slot, rank);
416 if (!s3resume)
417 gav(rw_test(rank + add));
418 if (!s3resume)
419 gav(rw_test(rank + add));
420 write_1d0(0, 0x142, 3, 1);
421 write_1d0(0, 0x103, 6, 1);
422
423 gav(get_580(channel, 0xc | (rank << 5)));
424 gav(read_1d0(0x142, 3));
425
Felix Held04be2dd2018-07-29 04:53:22 +0200426 MCHBAR8(0x5ff) = 0x0;
427 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100428}
429
430static void set_4cf(struct raminfo *info, int channel, u8 val)
431{
432 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
433 write_500(info, channel, val, 0x4cf, 4, 1);
434 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
435 write_500(info, channel, val, 0x659, 4, 1);
436 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
437 write_500(info, channel, val, 0x697, 4, 1);
438}
439
440static void set_334(int zero)
441{
442 int j, k, channel;
443 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
444 u32 vd8[2][16];
445
446 for (channel = 0; channel < NUM_CHANNELS; channel++) {
447 for (j = 0; j < 4; j++) {
448 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
449 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
450 u16 c;
451 if ((j == 0 || j == 3) && zero)
452 c = 0;
453 else if (j == 3)
454 c = 0x5f;
455 else
456 c = 0x5f5f;
457
458 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200459 MCHBAR32(0x138 + 8 * k) =
460 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100461 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200462 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100463 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200464 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100465 }
466
Felix Held22ca8cb2018-07-29 05:09:44 +0200467 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
468 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200469 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
470 zero ? 0 : (0x18191819 & lmask);
471 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
472 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
473 zero ? 0 : (a & lmask);
474 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
475 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100476 }
477 }
478
Felix Held04be2dd2018-07-29 04:53:22 +0200479 MCHBAR32_OR(0x130, 1);
480 while (MCHBAR8(0x130) & 1)
481 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100482}
483
484static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
485{
486 u32 v;
487 v = read_1d0(addr, split);
488 write_1d0((v & and) | or, addr, split, flag);
489}
490
491static int find_highest_bit_set(u16 val)
492{
493 int i;
494 for (i = 15; i >= 0; i--)
495 if (val & (1 << i))
496 return i;
497 return -1;
498}
499
500static int find_lowest_bit_set32(u32 val)
501{
502 int i;
503 for (i = 0; i < 32; i++)
504 if (val & (1 << i))
505 return i;
506 return -1;
507}
508
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100509enum {
510 DEVICE_TYPE = 2,
511 MODULE_TYPE = 3,
512 DENSITY = 4,
513 RANKS_AND_DQ = 7,
514 MEMORY_BUS_WIDTH = 8,
515 TIMEBASE_DIVIDEND = 10,
516 TIMEBASE_DIVISOR = 11,
517 CYCLETIME = 12,
518
519 CAS_LATENCIES_LSB = 14,
520 CAS_LATENCIES_MSB = 15,
521 CAS_LATENCY_TIME = 16,
522 THERMAL_AND_REFRESH = 31,
523 REFERENCE_RAW_CARD_USED = 62,
524 RANK1_ADDRESS_MAPPING = 63
525};
526
527static void calculate_timings(struct raminfo *info)
528{
Martin Roth468d02c2019-10-23 21:44:42 -0600529 unsigned int cycletime;
530 unsigned int cas_latency_time;
531 unsigned int supported_cas_latencies;
532 unsigned int channel, slot;
533 unsigned int clock_speed_index;
534 unsigned int min_cas_latency;
535 unsigned int cas_latency;
536 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100537
538 /* Find common CAS latency */
539 supported_cas_latencies = 0x3fe;
540 for (channel = 0; channel < NUM_CHANNELS; channel++)
541 for (slot = 0; slot < NUM_SLOTS; slot++)
542 if (info->populated_ranks[channel][slot][0])
543 supported_cas_latencies &=
544 2 *
545 (info->
546 spd[channel][slot][CAS_LATENCIES_LSB] |
547 (info->
548 spd[channel][slot][CAS_LATENCIES_MSB] <<
549 8));
550
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100551 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100552
553 cycletime = min_cycletime[max_clock_index];
554 cas_latency_time = min_cas_latency_time[max_clock_index];
555
556 for (channel = 0; channel < NUM_CHANNELS; channel++)
557 for (slot = 0; slot < NUM_SLOTS; slot++)
558 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600559 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100560 timebase =
561 1000 *
562 info->
563 spd[channel][slot][TIMEBASE_DIVIDEND] /
564 info->spd[channel][slot][TIMEBASE_DIVISOR];
565 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100566 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100567 timebase *
568 info->spd[channel][slot][CYCLETIME]);
569 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100570 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100571 timebase *
572 info->
573 spd[channel][slot][CAS_LATENCY_TIME]);
574 }
Jacob Garber3c193822019-06-10 18:23:32 -0600575 if (cycletime > min_cycletime[0])
576 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100577 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
578 if (cycletime == min_cycletime[clock_speed_index])
579 break;
580 if (cycletime > min_cycletime[clock_speed_index]) {
581 clock_speed_index--;
582 cycletime = min_cycletime[clock_speed_index];
583 break;
584 }
585 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100586 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100587 cas_latency = 0;
588 while (supported_cas_latencies) {
589 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
590 if (cas_latency <= min_cas_latency)
591 break;
592 supported_cas_latencies &=
593 ~(1 << find_highest_bit_set(supported_cas_latencies));
594 }
595
596 if (cas_latency != min_cas_latency && clock_speed_index)
597 clock_speed_index--;
598
599 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
600 die("Couldn't configure DRAM");
601 info->clock_speed_index = clock_speed_index;
602 info->cas_latency = cas_latency;
603}
604
605static void program_base_timings(struct raminfo *info)
606{
Martin Roth468d02c2019-10-23 21:44:42 -0600607 unsigned int channel;
608 unsigned int slot, rank, lane;
609 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100610 int i;
611
612 extended_silicon_revision = info->silicon_revision;
613 if (info->silicon_revision == 0)
614 for (channel = 0; channel < NUM_CHANNELS; channel++)
615 for (slot = 0; slot < NUM_SLOTS; slot++)
616 if ((info->
617 spd[channel][slot][MODULE_TYPE] & 0xF) ==
618 3)
619 extended_silicon_revision = 4;
620
621 for (channel = 0; channel < NUM_CHANNELS; channel++) {
622 for (slot = 0; slot < NUM_SLOTS; slot++)
623 for (rank = 0; rank < NUM_SLOTS; rank++) {
624 int card_timing_2;
625 if (!info->populated_ranks[channel][slot][rank])
626 continue;
627
628 for (lane = 0; lane < 9; lane++) {
629 int tm_reg;
630 int card_timing;
631
632 card_timing = 0;
633 if ((info->
634 spd[channel][slot][MODULE_TYPE] &
635 0xF) == 3) {
636 int reference_card;
637 reference_card =
638 info->
639 spd[channel][slot]
640 [REFERENCE_RAW_CARD_USED] &
641 0x1f;
642 if (reference_card == 3)
643 card_timing =
644 u16_ffd1188[0][lane]
645 [info->
646 clock_speed_index];
647 if (reference_card == 5)
648 card_timing =
649 u16_ffd1188[1][lane]
650 [info->
651 clock_speed_index];
652 }
653
654 info->training.
655 lane_timings[0][channel][slot][rank]
656 [lane] =
657 u8_FFFD1218[info->
658 clock_speed_index];
659 info->training.
660 lane_timings[1][channel][slot][rank]
661 [lane] = 256;
662
663 for (tm_reg = 2; tm_reg < 4; tm_reg++)
664 info->training.
665 lane_timings[tm_reg]
666 [channel][slot][rank][lane]
667 =
668 u8_FFFD1240[channel]
669 [extended_silicon_revision]
670 [lane][2 * slot +
671 rank][info->
672 clock_speed_index]
673 + info->max4048[channel]
674 +
675 u8_FFFD0C78[channel]
676 [extended_silicon_revision]
677 [info->
678 mode4030[channel]][slot]
679 [rank][info->
680 clock_speed_index]
681 + card_timing;
682 for (tm_reg = 0; tm_reg < 4; tm_reg++)
683 write_500(info, channel,
684 info->training.
685 lane_timings[tm_reg]
686 [channel][slot][rank]
687 [lane],
688 get_timing_register_addr
689 (lane, tm_reg, slot,
690 rank), 9, 0);
691 }
692
693 card_timing_2 = 0;
694 if (!(extended_silicon_revision != 4
695 || (info->
696 populated_ranks_mask[channel] & 5) ==
697 5)) {
698 if ((info->
699 spd[channel][slot]
700 [REFERENCE_RAW_CARD_USED] & 0x1F)
701 == 3)
702 card_timing_2 =
703 u16_FFFE0EB8[0][info->
704 clock_speed_index];
705 if ((info->
706 spd[channel][slot]
707 [REFERENCE_RAW_CARD_USED] & 0x1F)
708 == 5)
709 card_timing_2 =
710 u16_FFFE0EB8[1][info->
711 clock_speed_index];
712 }
713
714 for (i = 0; i < 3; i++)
715 write_500(info, channel,
716 (card_timing_2 +
717 info->max4048[channel]
718 +
719 u8_FFFD0EF8[channel]
720 [extended_silicon_revision]
721 [info->
722 mode4030[channel]][info->
723 clock_speed_index]),
724 u16_fffd0c50[i][slot][rank],
725 8, 1);
726 write_500(info, channel,
727 (info->max4048[channel] +
728 u8_FFFD0C78[channel]
729 [extended_silicon_revision][info->
730 mode4030
731 [channel]]
732 [slot][rank][info->
733 clock_speed_index]),
734 u16_fffd0c70[slot][rank], 7, 1);
735 }
736 if (!info->populated_ranks_mask[channel])
737 continue;
738 for (i = 0; i < 3; i++)
739 write_500(info, channel,
740 (info->max4048[channel] +
741 info->avg4044[channel]
742 +
743 u8_FFFD17E0[channel]
744 [extended_silicon_revision][info->
745 mode4030
746 [channel]][info->
747 clock_speed_index]),
748 u16_fffd0c68[i], 8, 1);
749 }
750}
751
752static unsigned int fsbcycle_ps(struct raminfo *info)
753{
754 return 900000 / info->fsb_frequency;
755}
756
757/* The time of DDR transfer in ps. */
758static unsigned int halfcycle_ps(struct raminfo *info)
759{
760 return 3750 / (info->clock_speed_index + 3);
761}
762
763/* The time of clock cycle in ps. */
764static unsigned int cycle_ps(struct raminfo *info)
765{
766 return 2 * halfcycle_ps(info);
767}
768
769/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600770static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100771{
772 return (info->clock_speed_index + 3) * 120;
773}
774
775/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600776static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100777{
778 return 100 * frequency_11(info) / 9;
779}
780
Martin Roth468d02c2019-10-23 21:44:42 -0600781static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100782{
783 return (frequency_11(info) * 2) * ps / 900000;
784}
785
Martin Roth468d02c2019-10-23 21:44:42 -0600786static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100787{
788 return (frequency_11(info)) * ns / 900;
789}
790
791static void compute_derived_timings(struct raminfo *info)
792{
Martin Roth468d02c2019-10-23 21:44:42 -0600793 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100794 int extended_silicon_revision;
795 int some_delay_1_ps;
796 int some_delay_2_ps;
797 int some_delay_2_halfcycles_ceil;
798 int some_delay_2_halfcycles_floor;
799 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100800 int some_delay_3_ps_rounded;
801 int some_delay_1_cycle_ceil;
802 int some_delay_1_cycle_floor;
803
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100804 some_delay_3_ps_rounded = 0;
805 extended_silicon_revision = info->silicon_revision;
806 if (!info->silicon_revision)
807 for (channel = 0; channel < NUM_CHANNELS; channel++)
808 for (slot = 0; slot < NUM_SLOTS; slot++)
809 if ((info->
810 spd[channel][slot][MODULE_TYPE] & 0xF) ==
811 3)
812 extended_silicon_revision = 4;
813 if (info->board_lane_delay[7] < 5)
814 info->board_lane_delay[7] = 5;
815 info->revision_flag_1 = 2;
816 if (info->silicon_revision == 2 || info->silicon_revision == 3)
817 info->revision_flag_1 = 0;
818 if (info->revision < 16)
819 info->revision_flag_1 = 0;
820
821 if (info->revision < 8)
822 info->revision_flag_1 = 0;
823 if (info->revision >= 8 && (info->silicon_revision == 0
824 || info->silicon_revision == 1))
825 some_delay_2_ps = 735;
826 else
827 some_delay_2_ps = 750;
828
829 if (info->revision >= 0x10 && (info->silicon_revision == 0
830 || info->silicon_revision == 1))
831 some_delay_1_ps = 3929;
832 else
833 some_delay_1_ps = 3490;
834
835 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
836 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
837 if (some_delay_1_ps % cycle_ps(info))
838 some_delay_1_cycle_ceil++;
839 else
840 some_delay_1_cycle_floor--;
841 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
842 if (info->revision_flag_1)
843 some_delay_2_ps = halfcycle_ps(info) >> 6;
844 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100845 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100846 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
847 375;
848 some_delay_3_ps =
849 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
850 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200851 if (some_delay_3_ps >= 150) {
852 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100853 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200854 some_delay_3_ps_rounded =
855 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
856 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100857 }
858 some_delay_2_halfcycles_ceil =
859 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
860 2 * (some_delay_1_cycle_ceil - 1);
861 if (info->revision_flag_1 && some_delay_3_ps < 150)
862 some_delay_2_halfcycles_ceil++;
863 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
864 if (info->revision < 0x10)
865 some_delay_2_halfcycles_floor =
866 some_delay_2_halfcycles_ceil - 1;
867 if (!info->revision_flag_1)
868 some_delay_2_halfcycles_floor++;
869 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
870 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
871 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
872 || (info->populated_ranks[1][0][0]
873 && info->populated_ranks[1][1][0]))
874 info->max_slots_used_in_channel = 2;
875 else
876 info->max_slots_used_in_channel = 1;
877 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200878 MCHBAR32(0x244 + (channel << 10)) =
879 ((info->revision < 8) ? 1 : 0x200) |
880 ((2 - info->max_slots_used_in_channel) << 17) |
881 (channel << 21) |
882 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100883 if (info->max_slots_used_in_channel == 1) {
884 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
885 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
886 } else {
887 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 */
888 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
889 || (count_ranks_in_channel(info, 1) ==
890 2)) ? 2 : 3;
891 }
892 for (channel = 0; channel < NUM_CHANNELS; channel++) {
893 int max_of_unk;
894 int min_of_unk_2;
895
896 int i, count;
897 int sum;
898
899 if (!info->populated_ranks_mask[channel])
900 continue;
901
902 max_of_unk = 0;
903 min_of_unk_2 = 32767;
904
905 sum = 0;
906 count = 0;
907 for (i = 0; i < 3; i++) {
908 int unk1;
909 if (info->revision < 8)
910 unk1 =
911 u8_FFFD1891[0][channel][info->
912 clock_speed_index]
913 [i];
914 else if (!
915 (info->revision >= 0x10
916 || info->revision_flag_1))
917 unk1 =
918 u8_FFFD1891[1][channel][info->
919 clock_speed_index]
920 [i];
921 else
922 unk1 = 0;
923 for (slot = 0; slot < NUM_SLOTS; slot++)
924 for (rank = 0; rank < NUM_RANKS; rank++) {
925 int a = 0;
926 int b = 0;
927
928 if (!info->
929 populated_ranks[channel][slot]
930 [rank])
931 continue;
932 if (extended_silicon_revision == 4
933 && (info->
934 populated_ranks_mask[channel] &
935 5) != 5) {
936 if ((info->
937 spd[channel][slot]
938 [REFERENCE_RAW_CARD_USED] &
939 0x1F) == 3) {
940 a = u16_ffd1178[0]
941 [info->
942 clock_speed_index];
943 b = u16_fe0eb8[0][info->
944 clock_speed_index];
945 } else
946 if ((info->
947 spd[channel][slot]
948 [REFERENCE_RAW_CARD_USED]
949 & 0x1F) == 5) {
950 a = u16_ffd1178[1]
951 [info->
952 clock_speed_index];
953 b = u16_fe0eb8[1][info->
954 clock_speed_index];
955 }
956 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100957 min_of_unk_2 = MIN(min_of_unk_2, a);
958 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100959 if (rank == 0) {
960 sum += a;
961 count++;
962 }
963 {
964 int t;
965 t = b +
966 u8_FFFD0EF8[channel]
967 [extended_silicon_revision]
968 [info->
969 mode4030[channel]][info->
970 clock_speed_index];
971 if (unk1 >= t)
972 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100973 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100974 unk1 - t);
975 }
976 }
977 {
978 int t =
979 u8_FFFD17E0[channel]
980 [extended_silicon_revision][info->
981 mode4030
982 [channel]]
983 [info->clock_speed_index] + min_of_unk_2;
984 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100985 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100986 }
987 }
988
Jacob Garber64fb4a32019-06-10 17:29:18 -0600989 if (count == 0)
990 die("No memory ranks found for channel %u\n", channel);
991
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100992 info->avg4044[channel] = sum / count;
993 info->max4048[channel] = max_of_unk;
994 }
995}
996
997static void jedec_read(struct raminfo *info,
998 int channel, int slot, int rank,
999 int total_rank, u8 addr3, unsigned int value)
1000{
1001 /* Handle mirrored mapping. */
1002 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001003 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1004 ((addr3 >> 1) & 0x10);
1005 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1006 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001007
1008 /* Handle mirrored mapping. */
1009 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1010 value =
1011 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1012 << 1);
1013
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001014 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001015
Felix Held04be2dd2018-07-29 04:53:22 +02001016 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1017 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001018
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001019 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001020}
1021
1022enum {
1023 MR1_RZQ12 = 512,
1024 MR1_RZQ2 = 64,
1025 MR1_RZQ4 = 4,
1026 MR1_ODS34OHM = 2
1027};
1028
1029enum {
1030 MR0_BT_INTERLEAVED = 8,
1031 MR0_DLL_RESET_ON = 256
1032};
1033
1034enum {
1035 MR2_RTT_WR_DISABLED = 0,
1036 MR2_RZQ2 = 1 << 10
1037};
1038
1039static void jedec_init(struct raminfo *info)
1040{
1041 int write_recovery;
1042 int channel, slot, rank;
1043 int total_rank;
1044 int dll_on;
1045 int self_refresh_temperature;
1046 int auto_self_refresh;
1047
1048 auto_self_refresh = 1;
1049 self_refresh_temperature = 1;
1050 if (info->board_lane_delay[3] <= 10) {
1051 if (info->board_lane_delay[3] <= 8)
1052 write_recovery = info->board_lane_delay[3] - 4;
1053 else
1054 write_recovery = 5;
1055 } else {
1056 write_recovery = 6;
1057 }
1058 FOR_POPULATED_RANKS {
1059 auto_self_refresh &=
1060 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1061 self_refresh_temperature &=
1062 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1063 }
1064 if (auto_self_refresh == 1)
1065 self_refresh_temperature = 0;
1066
1067 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1068 || (info->populated_ranks[0][0][0]
1069 && info->populated_ranks[0][1][0])
1070 || (info->populated_ranks[1][0][0]
1071 && info->populated_ranks[1][1][0]));
1072
1073 total_rank = 0;
1074
1075 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1076 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1077 int rzq_reg58e;
1078
1079 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1080 rzq_reg58e = 64;
1081 rtt = MR1_RZQ2;
1082 if (info->clock_speed_index != 0) {
1083 rzq_reg58e = 4;
1084 if (info->populated_ranks_mask[channel] == 3)
1085 rtt = MR1_RZQ4;
1086 }
1087 } else {
1088 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1089 rtt = MR1_RZQ12;
1090 rzq_reg58e = 64;
1091 rtt_wr = MR2_RZQ2;
1092 } else {
1093 rzq_reg58e = 4;
1094 rtt = MR1_RZQ4;
1095 }
1096 }
1097
Felix Held04be2dd2018-07-29 04:53:22 +02001098 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1099 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1100 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1101 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1102 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001103
1104 for (slot = 0; slot < NUM_SLOTS; slot++)
1105 for (rank = 0; rank < NUM_RANKS; rank++)
1106 if (info->populated_ranks[channel][slot][rank]) {
1107 jedec_read(info, channel, slot, rank,
1108 total_rank, 0x28,
1109 rtt_wr | (info->
1110 clock_speed_index
1111 << 3)
1112 | (auto_self_refresh << 6) |
1113 (self_refresh_temperature <<
1114 7));
1115 jedec_read(info, channel, slot, rank,
1116 total_rank, 0x38, 0);
1117 jedec_read(info, channel, slot, rank,
1118 total_rank, 0x18,
1119 rtt | MR1_ODS34OHM);
1120 jedec_read(info, channel, slot, rank,
1121 total_rank, 6,
1122 (dll_on << 12) |
1123 (write_recovery << 9)
1124 | ((info->cas_latency - 4) <<
1125 4) | MR0_BT_INTERLEAVED |
1126 MR0_DLL_RESET_ON);
1127 total_rank++;
1128 }
1129 }
1130}
1131
1132static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1133{
Martin Roth468d02c2019-10-23 21:44:42 -06001134 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001135 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1136 unsigned int channel_0_non_interleaved;
1137
1138 FOR_ALL_RANKS {
1139 if (info->populated_ranks[channel][slot][rank]) {
1140 total_mb[channel] +=
1141 pre_jedec ? 256 : (256 << info->
1142 density[channel][slot] >> info->
1143 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001144 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1145 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1146 (info->is_x16_module[channel][slot] |
1147 ((info->density[channel][slot] + 1) << 1))) |
1148 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001149 }
Felix Held04be2dd2018-07-29 04:53:22 +02001150 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1151 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001152 }
1153
1154 info->total_memory_mb = total_mb[0] + total_mb[1];
1155
1156 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001157 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001158 info->non_interleaved_part_mb =
1159 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1160 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001161 MCHBAR32(0x100) = channel_0_non_interleaved |
1162 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001163 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001164 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001165}
1166
1167static void program_board_delay(struct raminfo *info)
1168{
1169 int cas_latency_shift;
1170 int some_delay_ns;
1171 int some_delay_3_half_cycles;
1172
Martin Roth468d02c2019-10-23 21:44:42 -06001173 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174 int high_multiplier;
1175 int lane_3_delay;
1176 int cas_latency_derived;
1177
1178 high_multiplier = 0;
1179 some_delay_ns = 200;
1180 some_delay_3_half_cycles = 4;
1181 cas_latency_shift = info->silicon_revision == 0
1182 || info->silicon_revision == 1 ? 1 : 0;
1183 if (info->revision < 8) {
1184 some_delay_ns = 600;
1185 cas_latency_shift = 0;
1186 }
1187 {
1188 int speed_bit;
1189 speed_bit =
1190 ((info->clock_speed_index > 1
1191 || (info->silicon_revision != 2
1192 && info->silicon_revision != 3))) ^ (info->revision >=
1193 0x10);
1194 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1195 3, 1);
1196 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1197 3, 1);
1198 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1199 && (info->silicon_revision == 2
1200 || info->silicon_revision == 3))
1201 rmw_1d0(0x116, 5, 2, 4, 1);
1202 }
Felix Held04be2dd2018-07-29 04:53:22 +02001203 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1204 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001205
Felix Held04be2dd2018-07-29 04:53:22 +02001206 MCHBAR8(0x124) = info->board_lane_delay[4] +
1207 ((frequency_01(info) + 999) / 1000);
1208 MCHBAR16(0x125) = 0x1360;
1209 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001210 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001211 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 high_multiplier = 1;
1213 some_delay_2_half_cycles = ps_to_halfcycles(info,
1214 ((3 *
1215 fsbcycle_ps(info))
1216 >> 1) +
1217 (halfcycle_ps(info)
1218 *
1219 reg178_min[info->
1220 clock_speed_index]
1221 >> 6)
1222 +
1223 4 *
1224 halfcycle_ps(info)
1225 + 2230);
1226 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001227 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001228 (frequency_11(info) * 2) * (28 -
1229 some_delay_2_half_cycles) /
1230 (frequency_11(info) * 2 -
1231 4 * (info->fsb_frequency))) >> 3, 7);
1232 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001233 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001234 some_delay_3_half_cycles = 3;
1235 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001236 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1237 MCHBAR32(0x224 + (channel << 10)) =
1238 (info->max_slots_used_in_channel - 1) |
1239 ((info->cas_latency - 5 - info->clock_speed_index)
1240 << 21) | ((info->max_slots_used_in_channel +
1241 info->cas_latency - cas_latency_shift - 4) << 16) |
1242 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1243 ((info->cas_latency - info->clock_speed_index +
1244 info->max_slots_used_in_channel - 6) << 8);
1245 MCHBAR32(0x228 + (channel << 10)) =
1246 info->max_slots_used_in_channel;
1247 MCHBAR8(0x239 + (channel << 10)) = 32;
1248 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1249 (some_delay_3_half_cycles << 25) | 0x840000;
1250 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1251 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1252 MCHBAR32(0x24c + (channel << 10)) =
1253 ((!!info->clock_speed_index) << 17) |
1254 (((2 + info->clock_speed_index -
1255 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001256
Felix Held04be2dd2018-07-29 04:53:22 +02001257 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1258 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1259 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260
1261 write_500(info, channel,
1262 ((!info->populated_ranks[channel][1][1])
1263 | (!info->populated_ranks[channel][1][0] << 1)
1264 | (!info->populated_ranks[channel][0][1] << 2)
1265 | (!info->populated_ranks[channel][0][0] << 3)),
1266 0x4c9, 4, 1);
1267 }
1268
Felix Held22ca8cb2018-07-29 05:09:44 +02001269 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001270 {
1271 u8 freq_divisor = 2;
1272 if (info->fsb_frequency == frequency_11(info))
1273 freq_divisor = 3;
1274 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1275 freq_divisor = 1;
1276 else
1277 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001278 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279 }
1280
1281 if (info->board_lane_delay[3] <= 10) {
1282 if (info->board_lane_delay[3] <= 8)
1283 lane_3_delay = info->board_lane_delay[3];
1284 else
1285 lane_3_delay = 10;
1286 } else {
1287 lane_3_delay = 12;
1288 }
1289 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1290 if (info->clock_speed_index > 1)
1291 cas_latency_derived++;
1292 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001293 MCHBAR32(0x240 + (channel << 10)) =
1294 ((info->clock_speed_index == 0) * 0x11000) |
1295 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1296 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1298 0x609, 6, 1);
1299 write_500(info, channel,
1300 info->clock_speed_index + 2 * info->cas_latency - 7,
1301 0x601, 6, 1);
1302
Felix Held04be2dd2018-07-29 04:53:22 +02001303 MCHBAR32(0x250 + (channel << 10)) =
1304 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1305 (info->board_lane_delay[7] << 2) |
1306 (info->board_lane_delay[4] << 16) |
1307 (info->board_lane_delay[1] << 25) |
1308 (info->board_lane_delay[1] << 29) | 1;
1309 MCHBAR32(0x254 + (channel << 10)) =
1310 (info->board_lane_delay[1] >> 3) |
1311 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1312 0x80 | (info->board_lane_delay[6] << 1) |
1313 (info->board_lane_delay[2] << 28) |
1314 (cas_latency_derived << 16) | 0x4700000;
1315 MCHBAR32(0x258 + (channel << 10)) =
1316 ((info->board_lane_delay[5] + info->clock_speed_index +
1317 9) << 12) | ((info->clock_speed_index -
1318 info->cas_latency + 12) << 8) |
1319 (info->board_lane_delay[2] << 17) |
1320 (info->board_lane_delay[4] << 24) | 0x47;
1321 MCHBAR32(0x25c + (channel << 10)) =
1322 (info->board_lane_delay[1] << 1) |
1323 (info->board_lane_delay[0] << 8) | 0x1da50000;
1324 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1325 MCHBAR8(0x5f8 + (channel << 10)) =
1326 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001327 }
1328
1329 program_modules_memory_map(info, 1);
1330
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001331 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001332 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1333 MCHBAR16_OR(0x612, 0x100);
1334 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001335 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001336 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001337 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001338 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 }
1340}
1341
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001342#define DEFAULT_PCI_MMIO_SIZE 2048
1343#define HOST_BRIDGE PCI_DEVFN(0, 0)
1344
1345static unsigned int get_mmio_size(void)
1346{
1347 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001348 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001349
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001350 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001351 if (dev)
1352 cfg = dev->chip_info;
1353
1354 /* If this is zero, it just means devicetree.cb didn't set it */
1355 if (!cfg || cfg->pci_mmio_size == 0)
1356 return DEFAULT_PCI_MMIO_SIZE;
1357 else
1358 return cfg->pci_mmio_size;
1359}
1360
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361static void program_total_memory_map(struct raminfo *info)
1362{
Angel Pons9333b742020-07-22 16:04:15 +02001363 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001364 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001365 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001366 unsigned int uma_base_igd;
1367 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001368 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001369 int memory_remap;
1370 unsigned int memory_map[8];
1371 int i;
1372 unsigned int current_limit;
1373 unsigned int tseg_base;
1374 int uma_size_igd = 0, uma_size_gtt = 0;
1375
1376 memset(memory_map, 0, sizeof(memory_map));
1377
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001379 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001380 gav(t);
1381 const int uma_sizes_gtt[16] =
1382 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1383 /* Igd memory */
1384 const int uma_sizes_igd[16] = {
1385 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1386 256, 512
1387 };
1388
1389 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1390 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1391 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001392
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001393 mmio_size = get_mmio_size();
1394
Angel Pons9333b742020-07-22 16:04:15 +02001395 tom = info->total_memory_mb;
1396 if (tom == 4096)
1397 tom = 4032;
1398 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1399 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1400 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001402 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001404 remap_base = MAX(4096, touud);
1405 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 }
Angel Pons9333b742020-07-22 16:04:15 +02001407 if (touud > 4096)
1408 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001409 quickpath_reserved = 0;
1410
Angel Pons3ab19b32020-07-22 16:29:54 +02001411 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412
Jacob Garber975a7e32019-06-10 16:32:47 -06001413 gav(t);
1414
1415 if (t & 0x800) {
1416 u32 shift = t >> 20;
1417 if (shift == 0)
1418 die("Quickpath value is 0\n");
1419 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001420 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001421
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001423 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424
Angel Pons9333b742020-07-22 16:04:15 +02001425 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426 uma_base_gtt = uma_base_igd - uma_size_gtt;
1427 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1428 if (!memory_remap)
1429 tseg_base -= quickpath_reserved;
1430 tseg_base = ALIGN_DOWN(tseg_base, 8);
1431
Angel Pons16fe1e02020-07-22 16:12:33 +02001432 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1433 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001434 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001435 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1436 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001438 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439
1440 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001441 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1442 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001444 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445
1446 current_limit = 0;
1447 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1448 memory_map[1] = 4096;
1449 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001450 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001451 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1453 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001454 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 }
1456}
1457
1458static void collect_system_info(struct raminfo *info)
1459{
1460 u32 capid0[3];
1461 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001462 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463
1464 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001465 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1466 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001468 if (!info->memory_reserved_for_heci_mb) {
1469 /* Wait for ME to be ready */
1470 intel_early_me_init();
1471 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1472 }
1473
1474 for (i = 0; i < 3; i++)
1475 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001476 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001477 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001478 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1479
1480 if ((capid0[1] >> 11) & 1)
1481 info->uma_enabled = 0;
1482 else
1483 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001484 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001485 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1486 info->silicon_revision = 0;
1487
1488 if (capid0[2] & 2) {
1489 info->silicon_revision = 0;
1490 info->max_supported_clock_speed_index = 2;
1491 for (channel = 0; channel < NUM_CHANNELS; channel++)
1492 if (info->populated_ranks[channel][0][0]
1493 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1494 3) {
1495 info->silicon_revision = 2;
1496 info->max_supported_clock_speed_index = 1;
1497 }
1498 } else {
1499 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1500 case 1:
1501 case 2:
1502 info->silicon_revision = 3;
1503 break;
1504 case 3:
1505 info->silicon_revision = 0;
1506 break;
1507 case 0:
1508 info->silicon_revision = 2;
1509 break;
1510 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001511 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001512 case 0x40:
1513 info->silicon_revision = 0;
1514 break;
1515 case 0x48:
1516 info->silicon_revision = 1;
1517 break;
1518 }
1519 }
1520}
1521
1522static void write_training_data(struct raminfo *info)
1523{
1524 int tm, channel, slot, rank, lane;
1525 if (info->revision < 8)
1526 return;
1527
1528 for (tm = 0; tm < 4; tm++)
1529 for (channel = 0; channel < NUM_CHANNELS; channel++)
1530 for (slot = 0; slot < NUM_SLOTS; slot++)
1531 for (rank = 0; rank < NUM_RANKS; rank++)
1532 for (lane = 0; lane < 9; lane++)
1533 write_500(info, channel,
1534 info->
1535 cached_training->
1536 lane_timings[tm]
1537 [channel][slot][rank]
1538 [lane],
1539 get_timing_register_addr
1540 (lane, tm, slot,
1541 rank), 9, 0);
1542 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1543 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1544}
1545
1546static void dump_timings(struct raminfo *info)
1547{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001548 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001549 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001550 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001551 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001552 slot, rank);
1553 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001554 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001555 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001556 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 read_500(info, channel,
1558 get_timing_register_addr
1559 (lane, i, slot, rank),
1560 9),
1561 info->training.
1562 lane_timings[i][channel][slot][rank]
1563 [lane]);
1564 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001565 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001566 }
1567 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001568 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001570 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001571 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572}
1573
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001574/* Read timings and other registers that need to be restored verbatim and
1575 put them to CBMEM.
1576 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577static void save_timings(struct raminfo *info)
1578{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 int channel, slot, rank, lane, i;
1581
1582 train = info->training;
1583 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1584 for (i = 0; i < 4; i++)
1585 train.lane_timings[i][channel][slot][rank][lane] =
1586 read_500(info, channel,
1587 get_timing_register_addr(lane, i, slot,
1588 rank), 9);
1589 train.reg_178 = read_1d0(0x178, 7);
1590 train.reg_10b = read_1d0(0x10b, 6);
1591
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001592 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1593 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001594 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595 train.reg274265[channel][0] = reg32 >> 16;
1596 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001597 train.reg274265[channel][2] =
1598 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001599 }
Felix Held04be2dd2018-07-29 04:53:22 +02001600 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1601 train.reg_6dc = MCHBAR32(0x6dc);
1602 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001603
Arthur Heymansb3282092019-04-14 17:53:28 +02001604 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1605 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001606
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001608 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1609 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610}
1611
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001612static const struct ram_training *get_cached_training(void)
1613{
Shelley Chenad9cd682020-07-23 16:10:52 -07001614 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1615 MRC_CACHE_VERSION,
1616 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001617}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001618
1619/* FIXME: add timeout. */
1620static void wait_heci_ready(void)
1621{
Felix Held04be2dd2018-07-29 04:53:22 +02001622 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1623 ;
Angel Ponseb537932020-09-14 19:18:11 +02001624
1625 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626}
1627
1628/* FIXME: add timeout. */
1629static void wait_heci_cb_avail(int len)
1630{
1631 union {
1632 struct mei_csr csr;
1633 u32 raw;
1634 } csr;
1635
Felix Held22ca8cb2018-07-29 05:09:44 +02001636 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1637 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638
Angel Ponseb537932020-09-14 19:18:11 +02001639 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001640 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001641 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1642 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643}
1644
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001645static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646{
1647 int len = (head->length + 3) / 4;
1648 int i;
1649
1650 wait_heci_cb_avail(len + 1);
1651
1652 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001653 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001654 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001655 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001657 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1658 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659}
1660
Angel Ponseb537932020-09-14 19:18:11 +02001661static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001662{
1663 struct mei_header head;
1664 int maxlen;
1665
1666 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001667 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668
1669 while (len) {
1670 int cur = len;
1671 if (cur > maxlen) {
1672 cur = maxlen;
1673 head.is_complete = 0;
1674 } else
1675 head.is_complete = 1;
1676 head.length = cur;
1677 head.reserved = 0;
1678 head.client_address = clientaddress;
1679 head.host_address = hostaddress;
1680 send_heci_packet(&head, (u32 *) msg);
1681 len -= cur;
1682 msg += cur;
1683 }
1684}
1685
1686/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001687static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688{
1689 union {
1690 struct mei_csr csr;
1691 u32 raw;
1692 } csr;
1693 int i = 0;
1694
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001695 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001697 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001698 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1699
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001700 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001701 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001702 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001703 *packet_size = 0;
1704 return 0;
1705 }
Angel Ponseb537932020-09-14 19:18:11 +02001706 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001707 *packet_size = 0;
1708 return -1;
1709 }
1710
Angel Ponseb537932020-09-14 19:18:11 +02001711 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001712 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001713 } while (((head->length + 3) >> 2) >
1714 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001715
1716 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001717 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718 *packet_size = head->length;
1719 if (!csr.csr.ready)
1720 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001721 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001722 return 0;
1723}
1724
1725/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001726static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727{
1728 struct mei_header head;
1729 int current_position;
1730
1731 current_position = 0;
1732 while (1) {
1733 u32 current_size;
1734 current_size = *message_size - current_position;
1735 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001736 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001737 &current_size) == -1)
1738 break;
1739 if (!current_size)
1740 break;
1741 current_position += current_size;
1742 if (head.is_complete) {
1743 *message_size = current_position;
1744 return 0;
1745 }
1746
1747 if (current_position >= *message_size)
1748 break;
1749 }
1750 *message_size = 0;
1751 return -1;
1752}
1753
Angel Pons55f11e22020-09-14 19:06:53 +02001754static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001756 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757 u8 group_id;
1758 u8 command;
1759 u8 reserved;
1760 u8 result;
1761 u8 field2;
1762 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001763 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001764
1765 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1766 reply.command = 0;
1767
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001768 struct uma_message {
1769 u8 group_id;
1770 u8 cmd;
1771 u8 reserved;
1772 u8 result;
1773 u32 c2;
1774 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001775 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001776 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001777 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001778 .group_id = 0,
1779 .cmd = MKHI_SET_UMA,
1780 .reserved = 0,
1781 .result = 0,
1782 .c2 = 0x82,
1783 .heci_uma_addr = heci_uma_addr,
1784 .heci_uma_size = heci_uma_size,
1785 .c3 = 0,
1786 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001787 u32 reply_size;
1788
Angel Ponseb537932020-09-14 19:18:11 +02001789 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001790
1791 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001792 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001793 return;
1794
1795 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1796 die("HECI init failed\n");
1797}
1798
1799static void setup_heci_uma(struct raminfo *info)
1800{
Angel Pons298d34d2020-09-14 18:58:53 +02001801 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001802 return;
1803
Angel Pons36592bf2020-09-14 18:52:44 +02001804 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001805 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001806 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807 info->memory_reserved_for_heci_mb)) << 20;
1808
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001809 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001810 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001811 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001812 write32(DEFAULT_RCBA + 0x14, read32(DEFAULT_RCBA + 0x14) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001813 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001814 write32(DEFAULT_RCBA + 0x20, read32(DEFAULT_RCBA + 0x20) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001815 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001816 write32(DEFAULT_RCBA + 0x30, read32(DEFAULT_RCBA + 0x30) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001817 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001818 write32(DEFAULT_RCBA + 0x40, read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001819
Angel Ponseb537932020-09-14 19:18:11 +02001820 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001821 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001822
Felix Held04be2dd2018-07-29 04:53:22 +02001823 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
Angel Pons3b264d02020-09-15 00:25:49 +02001824 DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001825 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001826 }
1827
Felix Held04be2dd2018-07-29 04:53:22 +02001828 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001829
Angel Pons55f11e22020-09-14 19:06:53 +02001830 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001832 pci_write_config32(HECIDEV, 0x10, 0x0);
1833 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001834}
1835
1836static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1837{
1838 int ranks_in_channel;
1839 ranks_in_channel = info->populated_ranks[channel][0][0]
1840 + info->populated_ranks[channel][0][1]
1841 + info->populated_ranks[channel][1][0]
1842 + info->populated_ranks[channel][1][1];
1843
1844 /* empty channel */
1845 if (ranks_in_channel == 0)
1846 return 1;
1847
1848 if (ranks_in_channel != ranks)
1849 return 0;
1850 /* single slot */
1851 if (info->populated_ranks[channel][0][0] !=
1852 info->populated_ranks[channel][1][0])
1853 return 1;
1854 if (info->populated_ranks[channel][0][1] !=
1855 info->populated_ranks[channel][1][1])
1856 return 1;
1857 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1858 return 0;
1859 if (info->density[channel][0] != info->density[channel][1])
1860 return 0;
1861 return 1;
1862}
1863
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001864static void read_4090(struct raminfo *info)
1865{
1866 int i, channel, slot, rank, lane;
1867 for (i = 0; i < 2; i++)
1868 for (slot = 0; slot < NUM_SLOTS; slot++)
1869 for (rank = 0; rank < NUM_RANKS; rank++)
1870 for (lane = 0; lane < 9; lane++)
1871 info->training.
1872 lane_timings[0][i][slot][rank][lane]
1873 = 32;
1874
1875 for (i = 1; i < 4; i++)
1876 for (channel = 0; channel < NUM_CHANNELS; channel++)
1877 for (slot = 0; slot < NUM_SLOTS; slot++)
1878 for (rank = 0; rank < NUM_RANKS; rank++)
1879 for (lane = 0; lane < 9; lane++) {
1880 info->training.
1881 lane_timings[i][channel]
1882 [slot][rank][lane] =
1883 read_500(info, channel,
1884 get_timing_register_addr
1885 (lane, i, slot,
1886 rank), 9)
1887 + (i == 1) * 11; // !!!!
1888 }
1889
1890}
1891
1892static u32 get_etalon2(int flip, u32 addr)
1893{
1894 const u16 invmask[] = {
1895 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1896 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1897 };
1898 u32 ret;
1899 u32 comp4 = addr / 480;
1900 addr %= 480;
1901 u32 comp1 = addr & 0xf;
1902 u32 comp2 = (addr >> 4) & 1;
1903 u32 comp3 = addr >> 5;
1904
1905 if (comp4)
1906 ret = 0x1010101 << (comp4 - 1);
1907 else
1908 ret = 0;
1909 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1910 ret = ~ret;
1911
1912 return ret;
1913}
1914
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001915static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001916{
1917 msr_t msr = {.lo = 0, .hi = 0 };
1918
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001919 wrmsr(MTRR_PHYS_BASE(3), msr);
1920 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001921}
1922
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001923static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001924{
1925 msr_t msr;
1926 msr.lo = base | MTRR_TYPE_WRPROT;
1927 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001928 wrmsr(MTRR_PHYS_BASE(3), msr);
1929 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001930 & 0xffffffff);
1931 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001932 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001933}
1934
1935static void flush_cache(u32 start, u32 size)
1936{
1937 u32 end;
1938 u32 addr;
1939
1940 end = start + (ALIGN_DOWN(size + 4096, 4096));
1941 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001942 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001943}
1944
1945static void clear_errors(void)
1946{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001947 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001948}
1949
1950static void write_testing(struct raminfo *info, int totalrank, int flip)
1951{
1952 int nwrites = 0;
1953 /* in 8-byte units. */
1954 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001955 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001956
Patrick Rudolph819c2062019-11-29 19:27:37 +01001957 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958 for (offset = 0; offset < 9 * 480; offset += 2) {
1959 write32(base + offset * 8, get_etalon2(flip, offset));
1960 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1961 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1962 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1963 nwrites += 4;
1964 if (nwrites >= 320) {
1965 clear_errors();
1966 nwrites = 0;
1967 }
1968 }
1969}
1970
1971static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1972{
1973 u8 failmask = 0;
1974 int i;
1975 int comp1, comp2, comp3;
1976 u32 failxor[2] = { 0, 0 };
1977
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001978 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001979
1980 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1981 for (comp1 = 0; comp1 < 4; comp1++)
1982 for (comp2 = 0; comp2 < 60; comp2++) {
1983 u32 re[4];
1984 u32 curroffset =
1985 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1986 read128((total_rank << 28) | (curroffset << 3),
1987 (u64 *) re);
1988 failxor[0] |=
1989 get_etalon2(flip, curroffset) ^ re[0];
1990 failxor[1] |=
1991 get_etalon2(flip, curroffset) ^ re[1];
1992 failxor[0] |=
1993 get_etalon2(flip, curroffset | 1) ^ re[2];
1994 failxor[1] |=
1995 get_etalon2(flip, curroffset | 1) ^ re[3];
1996 }
1997 for (i = 0; i < 8; i++)
1998 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1999 failmask |= 1 << i;
2000 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002001 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002002 flush_cache((total_rank << 28), 1728 * 5 * 4);
2003 return failmask;
2004}
2005
2006const u32 seed1[0x18] = {
2007 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2008 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2009 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2010 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2011 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2012 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2013};
2014
2015static u32 get_seed2(int a, int b)
2016{
2017 const u32 seed2[5] = {
2018 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2019 0x5b6db6db,
2020 };
2021 u32 r;
2022 r = seed2[(a + (a >= 10)) / 5];
2023 return b ? ~r : r;
2024}
2025
2026static int make_shift(int comp2, int comp5, int x)
2027{
2028 const u8 seed3[32] = {
2029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2030 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2031 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2032 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2033 };
2034
2035 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2036}
2037
2038static u32 get_etalon(int flip, u32 addr)
2039{
2040 u32 mask_byte = 0;
2041 int comp1 = (addr >> 1) & 1;
2042 int comp2 = (addr >> 3) & 0x1f;
2043 int comp3 = (addr >> 8) & 0xf;
2044 int comp4 = (addr >> 12) & 0xf;
2045 int comp5 = (addr >> 16) & 0x1f;
2046 u32 mask_bit = ~(0x10001 << comp3);
2047 u32 part1;
2048 u32 part2;
2049 int byte;
2050
2051 part2 =
2052 ((seed1[comp5] >>
2053 make_shift(comp2, comp5,
2054 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2055 part1 =
2056 ((seed1[comp5] >>
2057 make_shift(comp2, comp5,
2058 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2059
2060 for (byte = 0; byte < 4; byte++)
2061 if ((get_seed2(comp5, comp4) >>
2062 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2063 mask_byte |= 0xff << (8 * byte);
2064
2065 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2066 (comp3 + 16));
2067}
2068
2069static void
2070write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2071 char flip)
2072{
2073 int i;
2074 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002075 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2076 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002077}
2078
2079static u8
2080check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2081 char flip)
2082{
2083 u8 failmask = 0;
2084 u32 failxor[2];
2085 int i;
2086 int comp1, comp2, comp3;
2087
2088 failxor[0] = 0;
2089 failxor[1] = 0;
2090
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002091 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002092 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2093 for (comp1 = 0; comp1 < 16; comp1++)
2094 for (comp2 = 0; comp2 < 64; comp2++) {
2095 u32 addr =
2096 (totalrank << 28) | (region << 25) | (block
2097 << 16)
2098 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2099 2);
2100 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002101 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002102 }
2103 for (i = 0; i < 8; i++)
2104 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2105 failmask |= 1 << i;
2106 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002107 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002108 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2109 return failmask;
2110}
2111
2112static int check_bounded(unsigned short *vals, u16 bound)
2113{
2114 int i;
2115
2116 for (i = 0; i < 8; i++)
2117 if (vals[i] < bound)
2118 return 0;
2119 return 1;
2120}
2121
2122enum state {
2123 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2124};
2125
2126static int validate_state(enum state *in)
2127{
2128 int i;
2129 for (i = 0; i < 8; i++)
2130 if (in[i] != COMPLETE)
2131 return 0;
2132 return 1;
2133}
2134
2135static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002136do_fsm(enum state *state, u16 *counter,
2137 u8 fail_mask, int margin, int uplimit,
2138 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002139{
2140 int lane;
2141
2142 for (lane = 0; lane < 8; lane++) {
2143 int is_fail = (fail_mask >> lane) & 1;
2144 switch (state[lane]) {
2145 case BEFORE_USABLE:
2146 if (!is_fail) {
2147 counter[lane] = 1;
2148 state[lane] = AT_USABLE;
2149 break;
2150 }
2151 counter[lane] = 0;
2152 state[lane] = BEFORE_USABLE;
2153 break;
2154 case AT_USABLE:
2155 if (!is_fail) {
2156 ++counter[lane];
2157 if (counter[lane] >= margin) {
2158 state[lane] = AT_MARGIN;
2159 res_low[lane] = val - margin + 1;
2160 break;
2161 }
2162 state[lane] = 1;
2163 break;
2164 }
2165 counter[lane] = 0;
2166 state[lane] = BEFORE_USABLE;
2167 break;
2168 case AT_MARGIN:
2169 if (is_fail) {
2170 state[lane] = COMPLETE;
2171 res_high[lane] = val - 1;
2172 } else {
2173 counter[lane]++;
2174 state[lane] = AT_MARGIN;
2175 if (val == uplimit) {
2176 state[lane] = COMPLETE;
2177 res_high[lane] = uplimit;
2178 }
2179 }
2180 break;
2181 case COMPLETE:
2182 break;
2183 }
2184 }
2185}
2186
2187static void
2188train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2189 u8 total_rank, u8 reg_178, int first_run, int niter,
2190 timing_bounds_t * timings)
2191{
2192 int lane;
2193 enum state state[8];
2194 u16 count[8];
2195 u8 lower_usable[8];
2196 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002197 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002198 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002199 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002200
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002201 for (i = 0; i < 8; i++)
2202 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002203
2204 if (!first_run) {
2205 int is_all_ok = 1;
2206 for (lane = 0; lane < 8; lane++)
2207 if (timings[reg_178][channel][slot][rank][lane].
2208 smallest ==
2209 timings[reg_178][channel][slot][rank][lane].
2210 largest) {
2211 timings[reg_178][channel][slot][rank][lane].
2212 smallest = 0;
2213 timings[reg_178][channel][slot][rank][lane].
2214 largest = 0;
2215 is_all_ok = 0;
2216 }
2217 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002218 for (i = 0; i < 8; i++)
2219 state[i] = COMPLETE;
2220 }
2221 }
2222
2223 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2224 u8 failmask = 0;
2225 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2226 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2227 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002228 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002229 do_fsm(state, count, failmask, 5, 47, lower_usable,
2230 upper_usable, reg1b3);
2231 }
2232
2233 if (reg1b3) {
2234 write_1d0(0, 0x1b3, 6, 1);
2235 write_1d0(0, 0x1a3, 6, 1);
2236 for (lane = 0; lane < 8; lane++) {
2237 if (state[lane] == COMPLETE) {
2238 timings[reg_178][channel][slot][rank][lane].
2239 smallest =
2240 lower_usable[lane] +
2241 (info->training.
2242 lane_timings[0][channel][slot][rank][lane]
2243 & 0x3F) - 32;
2244 timings[reg_178][channel][slot][rank][lane].
2245 largest =
2246 upper_usable[lane] +
2247 (info->training.
2248 lane_timings[0][channel][slot][rank][lane]
2249 & 0x3F) - 32;
2250 }
2251 }
2252 }
2253
2254 if (!first_run) {
2255 for (lane = 0; lane < 8; lane++)
2256 if (state[lane] == COMPLETE) {
2257 write_500(info, channel,
2258 timings[reg_178][channel][slot][rank]
2259 [lane].smallest,
2260 get_timing_register_addr(lane, 0,
2261 slot, rank),
2262 9, 1);
2263 write_500(info, channel,
2264 timings[reg_178][channel][slot][rank]
2265 [lane].smallest +
2266 info->training.
2267 lane_timings[1][channel][slot][rank]
2268 [lane]
2269 -
2270 info->training.
2271 lane_timings[0][channel][slot][rank]
2272 [lane], get_timing_register_addr(lane,
2273 1,
2274 slot,
2275 rank),
2276 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002277 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002278 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002279 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002280
2281 do {
2282 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002283 for (i = 0; i < niter; i++) {
2284 if (failmask == 0xFF)
2285 break;
2286 failmask |=
2287 check_testing_type2(info, total_rank, 2, i,
2288 0);
2289 failmask |=
2290 check_testing_type2(info, total_rank, 3, i,
2291 1);
2292 }
Felix Held04be2dd2018-07-29 04:53:22 +02002293 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002294 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002295 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296 if ((1 << lane) & failmask) {
2297 if (timings[reg_178][channel]
2298 [slot][rank][lane].
2299 largest <=
2300 timings[reg_178][channel]
2301 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002302 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002303 [lane] = -1;
2304 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 [lane] = 0;
2307 timings[reg_178]
2308 [channel][slot]
2309 [rank][lane].
2310 smallest++;
2311 write_500(info, channel,
2312 timings
2313 [reg_178]
2314 [channel]
2315 [slot][rank]
2316 [lane].
2317 smallest,
2318 get_timing_register_addr
2319 (lane, 0,
2320 slot, rank),
2321 9, 1);
2322 write_500(info, channel,
2323 timings
2324 [reg_178]
2325 [channel]
2326 [slot][rank]
2327 [lane].
2328 smallest +
2329 info->
2330 training.
2331 lane_timings
2332 [1][channel]
2333 [slot][rank]
2334 [lane]
2335 -
2336 info->
2337 training.
2338 lane_timings
2339 [0][channel]
2340 [slot][rank]
2341 [lane],
2342 get_timing_register_addr
2343 (lane, 1,
2344 slot, rank),
2345 9, 1);
2346 }
2347 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002348 num_successfully_checked[lane]
2349 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002350 }
2351 }
Felix Held04be2dd2018-07-29 04:53:22 +02002352 while (!check_bounded(num_successfully_checked, 2))
2353 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002354
2355 for (lane = 0; lane < 8; lane++)
2356 if (state[lane] == COMPLETE) {
2357 write_500(info, channel,
2358 timings[reg_178][channel][slot][rank]
2359 [lane].largest,
2360 get_timing_register_addr(lane, 0,
2361 slot, rank),
2362 9, 1);
2363 write_500(info, channel,
2364 timings[reg_178][channel][slot][rank]
2365 [lane].largest +
2366 info->training.
2367 lane_timings[1][channel][slot][rank]
2368 [lane]
2369 -
2370 info->training.
2371 lane_timings[0][channel][slot][rank]
2372 [lane], get_timing_register_addr(lane,
2373 1,
2374 slot,
2375 rank),
2376 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002377 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002378 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002379 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380
2381 do {
2382 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002383 for (i = 0; i < niter; i++) {
2384 if (failmask == 0xFF)
2385 break;
2386 failmask |=
2387 check_testing_type2(info, total_rank, 2, i,
2388 0);
2389 failmask |=
2390 check_testing_type2(info, total_rank, 3, i,
2391 1);
2392 }
2393
Felix Held04be2dd2018-07-29 04:53:22 +02002394 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002395 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002396 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397 if ((1 << lane) & failmask) {
2398 if (timings[reg_178][channel]
2399 [slot][rank][lane].
2400 largest <=
2401 timings[reg_178][channel]
2402 [slot][rank][lane].
2403 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002404 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002405 [lane] = -1;
2406 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002407 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002408 [lane] = 0;
2409 timings[reg_178]
2410 [channel][slot]
2411 [rank][lane].
2412 largest--;
2413 write_500(info, channel,
2414 timings
2415 [reg_178]
2416 [channel]
2417 [slot][rank]
2418 [lane].
2419 largest,
2420 get_timing_register_addr
2421 (lane, 0,
2422 slot, rank),
2423 9, 1);
2424 write_500(info, channel,
2425 timings
2426 [reg_178]
2427 [channel]
2428 [slot][rank]
2429 [lane].
2430 largest +
2431 info->
2432 training.
2433 lane_timings
2434 [1][channel]
2435 [slot][rank]
2436 [lane]
2437 -
2438 info->
2439 training.
2440 lane_timings
2441 [0][channel]
2442 [slot][rank]
2443 [lane],
2444 get_timing_register_addr
2445 (lane, 1,
2446 slot, rank),
2447 9, 1);
2448 }
2449 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002450 num_successfully_checked[lane]
2451 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002452 }
2453 }
2454 }
Felix Held04be2dd2018-07-29 04:53:22 +02002455 while (!check_bounded(num_successfully_checked, 3))
2456 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002457
2458 for (lane = 0; lane < 8; lane++) {
2459 write_500(info, channel,
2460 info->training.
2461 lane_timings[0][channel][slot][rank][lane],
2462 get_timing_register_addr(lane, 0, slot, rank),
2463 9, 1);
2464 write_500(info, channel,
2465 info->training.
2466 lane_timings[1][channel][slot][rank][lane],
2467 get_timing_register_addr(lane, 1, slot, rank),
2468 9, 1);
2469 if (timings[reg_178][channel][slot][rank][lane].
2470 largest <=
2471 timings[reg_178][channel][slot][rank][lane].
2472 smallest) {
2473 timings[reg_178][channel][slot][rank][lane].
2474 largest = 0;
2475 timings[reg_178][channel][slot][rank][lane].
2476 smallest = 0;
2477 }
2478 }
2479 }
2480}
2481
2482static void set_10b(struct raminfo *info, u8 val)
2483{
2484 int channel;
2485 int slot, rank;
2486 int lane;
2487
2488 if (read_1d0(0x10b, 6) == val)
2489 return;
2490
2491 write_1d0(val, 0x10b, 6, 1);
2492
2493 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2494 u16 reg_500;
2495 reg_500 = read_500(info, channel,
2496 get_timing_register_addr(lane, 0, slot,
2497 rank), 9);
2498 if (val == 1) {
2499 if (lut16[info->clock_speed_index] <= reg_500)
2500 reg_500 -= lut16[info->clock_speed_index];
2501 else
2502 reg_500 = 0;
2503 } else {
2504 reg_500 += lut16[info->clock_speed_index];
2505 }
2506 write_500(info, channel, reg_500,
2507 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2508 }
2509}
2510
2511static void set_ecc(int onoff)
2512{
2513 int channel;
2514 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2515 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002516 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002517 if (onoff)
2518 t |= 1;
2519 else
2520 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002521 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002522 }
2523}
2524
2525static void set_178(u8 val)
2526{
2527 if (val >= 31)
2528 val = val - 31;
2529 else
2530 val = 63 - val;
2531
2532 write_1d0(2 * val, 0x178, 7, 1);
2533}
2534
2535static void
2536write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2537 int type)
2538{
2539 int lane;
2540
2541 for (lane = 0; lane < 8; lane++)
2542 write_500(info, channel,
2543 info->training.
2544 lane_timings[type][channel][slot][rank][lane],
2545 get_timing_register_addr(lane, type, slot, rank), 9,
2546 0);
2547}
2548
2549static void
2550try_timing_offsets(struct raminfo *info, int channel,
2551 int slot, int rank, int totalrank)
2552{
2553 u16 count[8];
2554 enum state state[8];
2555 u8 lower_usable[8], upper_usable[8];
2556 int lane;
2557 int i;
2558 int flip = 1;
2559 int timing_offset;
2560
2561 for (i = 0; i < 8; i++)
2562 state[i] = BEFORE_USABLE;
2563
2564 memset(count, 0, sizeof(count));
2565
2566 for (lane = 0; lane < 8; lane++)
2567 write_500(info, channel,
2568 info->training.
2569 lane_timings[2][channel][slot][rank][lane] + 32,
2570 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2571
2572 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2573 timing_offset++) {
2574 u8 failmask;
2575 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2576 failmask = 0;
2577 for (i = 0; i < 2 && failmask != 0xff; i++) {
2578 flip = !flip;
2579 write_testing(info, totalrank, flip);
2580 failmask |= check_testing(info, totalrank, flip);
2581 }
2582 do_fsm(state, count, failmask, 10, 63, lower_usable,
2583 upper_usable, timing_offset);
2584 }
2585 write_1d0(0, 0x1bb, 6, 1);
2586 dump_timings(info);
2587 if (!validate_state(state))
2588 die("Couldn't discover DRAM timings (1)\n");
2589
2590 for (lane = 0; lane < 8; lane++) {
2591 u8 bias = 0;
2592
2593 if (info->silicon_revision) {
2594 int usable_length;
2595
2596 usable_length = upper_usable[lane] - lower_usable[lane];
2597 if (usable_length >= 20) {
2598 bias = usable_length / 2 - 10;
2599 if (bias >= 2)
2600 bias = 2;
2601 }
2602 }
2603 write_500(info, channel,
2604 info->training.
2605 lane_timings[2][channel][slot][rank][lane] +
2606 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2607 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2608 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2609 info->training.lane_timings[2][channel][slot][rank][lane] +
2610 lower_usable[lane];
2611 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2612 info->training.lane_timings[2][channel][slot][rank][lane] +
2613 upper_usable[lane];
2614 info->training.timing2_offset[channel][slot][rank][lane] =
2615 info->training.lane_timings[2][channel][slot][rank][lane];
2616 }
2617}
2618
2619static u8
2620choose_training(struct raminfo *info, int channel, int slot, int rank,
2621 int lane, timing_bounds_t * timings, u8 center_178)
2622{
2623 u16 central_weight;
2624 u16 side_weight;
2625 unsigned int sum = 0, count = 0;
2626 u8 span;
2627 u8 lower_margin, upper_margin;
2628 u8 reg_178;
2629 u8 result;
2630
2631 span = 12;
2632 central_weight = 20;
2633 side_weight = 20;
2634 if (info->silicon_revision == 1 && channel == 1) {
2635 central_weight = 5;
2636 side_weight = 20;
2637 if ((info->
2638 populated_ranks_mask[1] ^ (info->
2639 populated_ranks_mask[1] >> 2)) &
2640 1)
2641 span = 18;
2642 }
2643 if ((info->populated_ranks_mask[0] & 5) == 5) {
2644 central_weight = 20;
2645 side_weight = 20;
2646 }
2647 if (info->clock_speed_index >= 2
2648 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2649 if (info->silicon_revision == 1) {
2650 switch (channel) {
2651 case 0:
2652 if (lane == 1) {
2653 central_weight = 10;
2654 side_weight = 20;
2655 }
2656 break;
2657 case 1:
2658 if (lane == 6) {
2659 side_weight = 5;
2660 central_weight = 20;
2661 }
2662 break;
2663 }
2664 }
2665 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2666 side_weight = 5;
2667 central_weight = 20;
2668 }
2669 }
2670 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2671 reg_178 += span) {
2672 u8 smallest;
2673 u8 largest;
2674 largest = timings[reg_178][channel][slot][rank][lane].largest;
2675 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2676 if (largest - smallest + 1 >= 5) {
2677 unsigned int weight;
2678 if (reg_178 == center_178)
2679 weight = central_weight;
2680 else
2681 weight = side_weight;
2682 sum += weight * (largest + smallest);
2683 count += weight;
2684 }
2685 }
2686 dump_timings(info);
2687 if (count == 0)
2688 die("Couldn't discover DRAM timings (2)\n");
2689 result = sum / (2 * count);
2690 lower_margin =
2691 result - timings[center_178][channel][slot][rank][lane].smallest;
2692 upper_margin =
2693 timings[center_178][channel][slot][rank][lane].largest - result;
2694 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002695 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002696 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002697 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002698 return result;
2699}
2700
2701#define STANDARD_MIN_MARGIN 5
2702
2703static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2704{
2705 u16 margin[64];
2706 int lane, rank, slot, channel;
2707 u8 reg178;
2708 int count = 0, sum = 0;
2709
2710 for (reg178 = reg178_min[info->clock_speed_index];
2711 reg178 < reg178_max[info->clock_speed_index];
2712 reg178 += reg178_step[info->clock_speed_index]) {
2713 margin[reg178] = -1;
2714 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2715 int curmargin =
2716 timings[reg178][channel][slot][rank][lane].largest -
2717 timings[reg178][channel][slot][rank][lane].
2718 smallest + 1;
2719 if (curmargin < margin[reg178])
2720 margin[reg178] = curmargin;
2721 }
2722 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2723 u16 weight;
2724 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2725 sum += weight * reg178;
2726 count += weight;
2727 }
2728 }
2729 dump_timings(info);
2730 if (count == 0)
2731 die("Couldn't discover DRAM timings (3)\n");
2732
2733 u8 threshold;
2734
2735 for (threshold = 30; threshold >= 5; threshold--) {
2736 int usable_length = 0;
2737 int smallest_fount = 0;
2738 for (reg178 = reg178_min[info->clock_speed_index];
2739 reg178 < reg178_max[info->clock_speed_index];
2740 reg178 += reg178_step[info->clock_speed_index])
2741 if (margin[reg178] >= threshold) {
2742 usable_length +=
2743 reg178_step[info->clock_speed_index];
2744 info->training.reg178_largest =
2745 reg178 -
2746 2 * reg178_step[info->clock_speed_index];
2747
2748 if (!smallest_fount) {
2749 smallest_fount = 1;
2750 info->training.reg178_smallest =
2751 reg178 +
2752 reg178_step[info->
2753 clock_speed_index];
2754 }
2755 }
2756 if (usable_length >= 0x21)
2757 break;
2758 }
2759
2760 return sum / count;
2761}
2762
2763static int check_cached_sanity(struct raminfo *info)
2764{
2765 int lane;
2766 int slot, rank;
2767 int channel;
2768
2769 if (!info->cached_training)
2770 return 0;
2771
2772 for (channel = 0; channel < NUM_CHANNELS; channel++)
2773 for (slot = 0; slot < NUM_SLOTS; slot++)
2774 for (rank = 0; rank < NUM_RANKS; rank++)
2775 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2776 u16 cached_value, estimation_value;
2777 cached_value =
2778 info->cached_training->
2779 lane_timings[1][channel][slot][rank]
2780 [lane];
2781 if (cached_value >= 0x18
2782 && cached_value <= 0x1E7) {
2783 estimation_value =
2784 info->training.
2785 lane_timings[1][channel]
2786 [slot][rank][lane];
2787 if (estimation_value <
2788 cached_value - 24)
2789 return 0;
2790 if (estimation_value >
2791 cached_value + 24)
2792 return 0;
2793 }
2794 }
2795 return 1;
2796}
2797
2798static int try_cached_training(struct raminfo *info)
2799{
2800 u8 saved_243[2];
2801 u8 tm;
2802
2803 int channel, slot, rank, lane;
2804 int flip = 1;
2805 int i, j;
2806
2807 if (!check_cached_sanity(info))
2808 return 0;
2809
2810 info->training.reg178_center = info->cached_training->reg178_center;
2811 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2812 info->training.reg178_largest = info->cached_training->reg178_largest;
2813 memcpy(&info->training.timing_bounds,
2814 &info->cached_training->timing_bounds,
2815 sizeof(info->training.timing_bounds));
2816 memcpy(&info->training.timing_offset,
2817 &info->cached_training->timing_offset,
2818 sizeof(info->training.timing_offset));
2819
2820 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002821 saved_243[0] = MCHBAR8(0x243);
2822 saved_243[1] = MCHBAR8(0x643);
2823 MCHBAR8(0x243) = saved_243[0] | 2;
2824 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002825 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002826 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002827 if (read_1d0(0x10b, 6) & 1)
2828 set_10b(info, 0);
2829 for (tm = 0; tm < 2; tm++) {
2830 int totalrank;
2831
2832 set_178(tm ? info->cached_training->reg178_largest : info->
2833 cached_training->reg178_smallest);
2834
2835 totalrank = 0;
2836 /* Check timing ranges. With i == 0 we check smallest one and with
2837 i == 1 the largest bound. With j == 0 we check that on the bound
2838 it still works whereas with j == 1 we check that just outside of
2839 bound we fail.
2840 */
2841 FOR_POPULATED_RANKS_BACKWARDS {
2842 for (i = 0; i < 2; i++) {
2843 for (lane = 0; lane < 8; lane++) {
2844 write_500(info, channel,
2845 info->cached_training->
2846 timing2_bounds[channel][slot]
2847 [rank][lane][i],
2848 get_timing_register_addr(lane,
2849 3,
2850 slot,
2851 rank),
2852 9, 1);
2853
2854 if (!i)
2855 write_500(info, channel,
2856 info->
2857 cached_training->
2858 timing2_offset
2859 [channel][slot][rank]
2860 [lane],
2861 get_timing_register_addr
2862 (lane, 2, slot, rank),
2863 9, 1);
2864 write_500(info, channel,
2865 i ? info->cached_training->
2866 timing_bounds[tm][channel]
2867 [slot][rank][lane].
2868 largest : info->
2869 cached_training->
2870 timing_bounds[tm][channel]
2871 [slot][rank][lane].smallest,
2872 get_timing_register_addr(lane,
2873 0,
2874 slot,
2875 rank),
2876 9, 1);
2877 write_500(info, channel,
2878 info->cached_training->
2879 timing_offset[channel][slot]
2880 [rank][lane] +
2881 (i ? info->cached_training->
2882 timing_bounds[tm][channel]
2883 [slot][rank][lane].
2884 largest : info->
2885 cached_training->
2886 timing_bounds[tm][channel]
2887 [slot][rank][lane].
2888 smallest) - 64,
2889 get_timing_register_addr(lane,
2890 1,
2891 slot,
2892 rank),
2893 9, 1);
2894 }
2895 for (j = 0; j < 2; j++) {
2896 u8 failmask;
2897 u8 expected_failmask;
2898 char reg1b3;
2899
2900 reg1b3 = (j == 1) + 4;
2901 reg1b3 =
2902 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2903 write_1d0(reg1b3, 0x1bb, 6, 1);
2904 write_1d0(reg1b3, 0x1b3, 6, 1);
2905 write_1d0(reg1b3, 0x1a3, 6, 1);
2906
2907 flip = !flip;
2908 write_testing(info, totalrank, flip);
2909 failmask =
2910 check_testing(info, totalrank,
2911 flip);
2912 expected_failmask =
2913 j == 0 ? 0x00 : 0xff;
2914 if (failmask != expected_failmask)
2915 goto fail;
2916 }
2917 }
2918 totalrank++;
2919 }
2920 }
2921
2922 set_178(info->cached_training->reg178_center);
2923 if (info->use_ecc)
2924 set_ecc(1);
2925 write_training_data(info);
2926 write_1d0(0, 322, 3, 1);
2927 info->training = *info->cached_training;
2928
2929 write_1d0(0, 0x1bb, 6, 1);
2930 write_1d0(0, 0x1b3, 6, 1);
2931 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002932 MCHBAR8(0x243) = saved_243[0];
2933 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002934
2935 return 1;
2936
2937fail:
2938 FOR_POPULATED_RANKS {
2939 write_500_timings_type(info, channel, slot, rank, 1);
2940 write_500_timings_type(info, channel, slot, rank, 2);
2941 write_500_timings_type(info, channel, slot, rank, 3);
2942 }
2943
2944 write_1d0(0, 0x1bb, 6, 1);
2945 write_1d0(0, 0x1b3, 6, 1);
2946 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002947 MCHBAR8(0x243) = saved_243[0];
2948 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002949
2950 return 0;
2951}
2952
2953static void do_ram_training(struct raminfo *info)
2954{
2955 u8 saved_243[2];
2956 int totalrank = 0;
2957 u8 reg_178;
2958 int niter;
2959
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002960 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002961 int lane, rank, slot, channel;
2962 u8 reg178_center;
2963
2964 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002965 saved_243[0] = MCHBAR8(0x243);
2966 saved_243[1] = MCHBAR8(0x643);
2967 MCHBAR8(0x243) = saved_243[0] | 2;
2968 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002969 switch (info->clock_speed_index) {
2970 case 0:
2971 niter = 5;
2972 break;
2973 case 1:
2974 niter = 10;
2975 break;
2976 default:
2977 niter = 19;
2978 break;
2979 }
2980 set_ecc(0);
2981
2982 FOR_POPULATED_RANKS_BACKWARDS {
2983 int i;
2984
2985 write_500_timings_type(info, channel, slot, rank, 0);
2986
2987 write_testing(info, totalrank, 0);
2988 for (i = 0; i < niter; i++) {
2989 write_testing_type2(info, totalrank, 2, i, 0);
2990 write_testing_type2(info, totalrank, 3, i, 1);
2991 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002992 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002993 totalrank++;
2994 }
2995
2996 if (reg178_min[info->clock_speed_index] <
2997 reg178_max[info->clock_speed_index])
2998 memset(timings[reg178_min[info->clock_speed_index]], 0,
2999 sizeof(timings[0]) *
3000 (reg178_max[info->clock_speed_index] -
3001 reg178_min[info->clock_speed_index]));
3002 for (reg_178 = reg178_min[info->clock_speed_index];
3003 reg_178 < reg178_max[info->clock_speed_index];
3004 reg_178 += reg178_step[info->clock_speed_index]) {
3005 totalrank = 0;
3006 set_178(reg_178);
3007 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3008 for (slot = 0; slot < NUM_SLOTS; slot++)
3009 for (rank = 0; rank < NUM_RANKS; rank++) {
3010 memset(&timings[reg_178][channel][slot]
3011 [rank][0].smallest, 0, 16);
3012 if (info->
3013 populated_ranks[channel][slot]
3014 [rank]) {
3015 train_ram_at_178(info, channel,
3016 slot, rank,
3017 totalrank,
3018 reg_178, 1,
3019 niter,
3020 timings);
3021 totalrank++;
3022 }
3023 }
3024 }
3025
3026 reg178_center = choose_reg178(info, timings);
3027
3028 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3029 info->training.timing_bounds[0][channel][slot][rank][lane].
3030 smallest =
3031 timings[info->training.
3032 reg178_smallest][channel][slot][rank][lane].
3033 smallest;
3034 info->training.timing_bounds[0][channel][slot][rank][lane].
3035 largest =
3036 timings[info->training.
3037 reg178_smallest][channel][slot][rank][lane].largest;
3038 info->training.timing_bounds[1][channel][slot][rank][lane].
3039 smallest =
3040 timings[info->training.
3041 reg178_largest][channel][slot][rank][lane].smallest;
3042 info->training.timing_bounds[1][channel][slot][rank][lane].
3043 largest =
3044 timings[info->training.
3045 reg178_largest][channel][slot][rank][lane].largest;
3046 info->training.timing_offset[channel][slot][rank][lane] =
3047 info->training.lane_timings[1][channel][slot][rank][lane]
3048 -
3049 info->training.lane_timings[0][channel][slot][rank][lane] +
3050 64;
3051 }
3052
3053 if (info->silicon_revision == 1
3054 && (info->
3055 populated_ranks_mask[1] ^ (info->
3056 populated_ranks_mask[1] >> 2)) & 1) {
3057 int ranks_after_channel1;
3058
3059 totalrank = 0;
3060 for (reg_178 = reg178_center - 18;
3061 reg_178 <= reg178_center + 18; reg_178 += 18) {
3062 totalrank = 0;
3063 set_178(reg_178);
3064 for (slot = 0; slot < NUM_SLOTS; slot++)
3065 for (rank = 0; rank < NUM_RANKS; rank++) {
3066 if (info->
3067 populated_ranks[1][slot][rank]) {
3068 train_ram_at_178(info, 1, slot,
3069 rank,
3070 totalrank,
3071 reg_178, 0,
3072 niter,
3073 timings);
3074 totalrank++;
3075 }
3076 }
3077 }
3078 ranks_after_channel1 = totalrank;
3079
3080 for (reg_178 = reg178_center - 12;
3081 reg_178 <= reg178_center + 12; reg_178 += 12) {
3082 totalrank = ranks_after_channel1;
3083 set_178(reg_178);
3084 for (slot = 0; slot < NUM_SLOTS; slot++)
3085 for (rank = 0; rank < NUM_RANKS; rank++)
3086 if (info->
3087 populated_ranks[0][slot][rank]) {
3088 train_ram_at_178(info, 0, slot,
3089 rank,
3090 totalrank,
3091 reg_178, 0,
3092 niter,
3093 timings);
3094 totalrank++;
3095 }
3096
3097 }
3098 } else {
3099 for (reg_178 = reg178_center - 12;
3100 reg_178 <= reg178_center + 12; reg_178 += 12) {
3101 totalrank = 0;
3102 set_178(reg_178);
3103 FOR_POPULATED_RANKS_BACKWARDS {
3104 train_ram_at_178(info, channel, slot, rank,
3105 totalrank, reg_178, 0, niter,
3106 timings);
3107 totalrank++;
3108 }
3109 }
3110 }
3111
3112 set_178(reg178_center);
3113 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3114 u16 tm0;
3115
3116 tm0 =
3117 choose_training(info, channel, slot, rank, lane, timings,
3118 reg178_center);
3119 write_500(info, channel, tm0,
3120 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3121 write_500(info, channel,
3122 tm0 +
3123 info->training.
3124 lane_timings[1][channel][slot][rank][lane] -
3125 info->training.
3126 lane_timings[0][channel][slot][rank][lane],
3127 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3128 }
3129
3130 totalrank = 0;
3131 FOR_POPULATED_RANKS_BACKWARDS {
3132 try_timing_offsets(info, channel, slot, rank, totalrank);
3133 totalrank++;
3134 }
Felix Held04be2dd2018-07-29 04:53:22 +02003135 MCHBAR8(0x243) = saved_243[0];
3136 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003137 write_1d0(0, 0x142, 3, 1);
3138 info->training.reg178_center = reg178_center;
3139}
3140
3141static void ram_training(struct raminfo *info)
3142{
3143 u16 saved_fc4;
3144
Felix Held04be2dd2018-07-29 04:53:22 +02003145 saved_fc4 = MCHBAR16(0xfc4);
3146 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003147
3148 if (info->revision >= 8)
3149 read_4090(info);
3150
3151 if (!try_cached_training(info))
3152 do_ram_training(info);
3153 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3154 && info->clock_speed_index < 2)
3155 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003156 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003157}
3158
Martin Roth468d02c2019-10-23 21:44:42 -06003159static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003160{
Martin Roth468d02c2019-10-23 21:44:42 -06003161 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003162 if (a > b) {
3163 t = a;
3164 a = b;
3165 b = t;
3166 }
3167 /* invariant a < b. */
3168 while (a) {
3169 t = b % a;
3170 b = a;
3171 a = t;
3172 }
3173 return b;
3174}
3175
3176static inline int div_roundup(int a, int b)
3177{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003178 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003179}
3180
Martin Roth468d02c2019-10-23 21:44:42 -06003181static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003182{
3183 return (a * b) / gcd(a, b);
3184}
3185
3186struct stru1 {
3187 u8 freqs_reversed;
3188 u8 freq_diff_reduced;
3189 u8 freq_min_reduced;
3190 u8 divisor_f4_to_fmax;
3191 u8 divisor_f3_to_fmax;
3192 u8 freq4_to_max_remainder;
3193 u8 freq3_to_2_remainder;
3194 u8 freq3_to_2_remaindera;
3195 u8 freq4_to_2_remainder;
3196 int divisor_f3_to_f1, divisor_f4_to_f2;
3197 int common_time_unit_ps;
3198 int freq_max_reduced;
3199};
3200
3201static void
3202compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3203 int num_cycles_2, int num_cycles_1, int round_it,
3204 int add_freqs, struct stru1 *result)
3205{
3206 int g;
3207 int common_time_unit_ps;
3208 int freq1_reduced, freq2_reduced;
3209 int freq_min_reduced;
3210 int freq_max_reduced;
3211 int freq3, freq4;
3212
3213 g = gcd(freq1, freq2);
3214 freq1_reduced = freq1 / g;
3215 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003216 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3217 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003218
3219 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3220 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3221 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3222 if (add_freqs) {
3223 freq3 += freq2_reduced;
3224 freq4 += freq1_reduced;
3225 }
3226
3227 if (round_it) {
3228 result->freq3_to_2_remainder = 0;
3229 result->freq3_to_2_remaindera = 0;
3230 result->freq4_to_max_remainder = 0;
3231 result->divisor_f4_to_f2 = 0;
3232 result->divisor_f3_to_f1 = 0;
3233 } else {
3234 if (freq2_reduced < freq1_reduced) {
3235 result->freq3_to_2_remainder =
3236 result->freq3_to_2_remaindera =
3237 freq3 % freq1_reduced - freq1_reduced + 1;
3238 result->freq4_to_max_remainder =
3239 -(freq4 % freq1_reduced);
3240 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3241 result->divisor_f4_to_f2 =
3242 (freq4 -
3243 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3244 result->freq4_to_2_remainder =
3245 -(char)((freq1_reduced - freq2_reduced) +
3246 ((u8) freq4 -
3247 (freq1_reduced -
3248 freq2_reduced)) % (u8) freq2_reduced);
3249 } else {
3250 if (freq2_reduced > freq1_reduced) {
3251 result->freq4_to_max_remainder =
3252 (freq4 % freq2_reduced) - freq2_reduced + 1;
3253 result->freq4_to_2_remainder =
3254 freq4 % freq_max_reduced -
3255 freq_max_reduced + 1;
3256 } else {
3257 result->freq4_to_max_remainder =
3258 -(freq4 % freq2_reduced);
3259 result->freq4_to_2_remainder =
3260 -(char)(freq4 % freq_max_reduced);
3261 }
3262 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3263 result->divisor_f3_to_f1 =
3264 (freq3 -
3265 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3266 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3267 result->freq3_to_2_remaindera =
3268 -(char)((freq_max_reduced - freq_min_reduced) +
3269 (freq3 -
3270 (freq_max_reduced -
3271 freq_min_reduced)) % freq1_reduced);
3272 }
3273 }
3274 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3275 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3276 if (round_it) {
3277 if (freq2_reduced > freq1_reduced) {
3278 if (freq3 % freq_max_reduced)
3279 result->divisor_f3_to_fmax++;
3280 }
3281 if (freq2_reduced < freq1_reduced) {
3282 if (freq4 % freq_max_reduced)
3283 result->divisor_f4_to_fmax++;
3284 }
3285 }
3286 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3287 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3288 result->freq_min_reduced = freq_min_reduced;
3289 result->common_time_unit_ps = common_time_unit_ps;
3290 result->freq_max_reduced = freq_max_reduced;
3291}
3292
3293static void
3294set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3295 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3296 int num_cycles_4, int reverse)
3297{
3298 struct stru1 vv;
3299 char multiplier;
3300
3301 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3302 0, 1, &vv);
3303
3304 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003305 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003306 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3307 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3308 div_roundup(num_cycles_1,
3309 vv.common_time_unit_ps) +
3310 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3311 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3312
3313 u32 y =
3314 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3315 vv.freq_max_reduced * multiplier)
3316 | (vv.
3317 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3318 multiplier) << 16) | ((u8) (vv.
3319 freq_min_reduced
3320 *
3321 multiplier)
3322 << 24);
3323 u32 x =
3324 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3325 divisor_f3_to_f1
3326 << 16)
3327 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3328 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003329 MCHBAR32(reg) = y;
3330 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003331 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003332 MCHBAR32(reg + 4) = y;
3333 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003334 }
3335}
3336
3337static void
3338set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3339 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3340 int num_cycles_4)
3341{
3342 struct stru1 ratios1;
3343 struct stru1 ratios2;
3344
3345 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3346 0, 1, &ratios2);
3347 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3348 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003349 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003350 ratios1.freq4_to_max_remainder | (ratios2.
3351 freq4_to_max_remainder
3352 << 8)
3353 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3354 divisor_f4_to_fmax
3355 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003356 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3357 (ratios2.freq4_to_max_remainder << 8) |
3358 (ratios1.divisor_f4_to_fmax << 16) |
3359 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003360}
3361
3362static void
3363set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3364 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3365{
3366 struct stru1 ratios;
3367
3368 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3369 round_it, add_freqs, &ratios);
3370 switch (mode) {
3371 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003372 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3373 (ratios.freqs_reversed << 8);
3374 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3375 (ratios.freq4_to_max_remainder << 8) |
3376 (ratios.divisor_f3_to_fmax << 16) |
3377 (ratios.divisor_f4_to_fmax << 20) |
3378 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003379 break;
3380
3381 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003382 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3383 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003384 break;
3385
3386 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003387 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3388 (ratios.freq4_to_max_remainder << 8) |
3389 (ratios.divisor_f3_to_fmax << 16) |
3390 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003391 break;
3392
3393 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003394 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3395 (ratios.divisor_f4_to_fmax << 8) |
3396 (ratios.freqs_reversed << 12) |
3397 (ratios.freq_min_reduced << 16) |
3398 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003399 break;
3400 }
3401}
3402
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003403static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003404{
3405 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3406 0, 1);
3407 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3408 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3409 1);
3410 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3411 frequency_11(info), 1231, 1524, 0, 1);
3412 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3413 frequency_11(info) / 2, 1278, 2008, 0, 1);
3414 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3415 1167, 1539, 0, 1);
3416 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3417 frequency_11(info) / 2, 1403, 1318, 0, 1);
3418 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3419 1);
3420 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3421 1);
3422 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3423 1, 1);
3424 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3425 1);
3426 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3427 frequency_11(info) / 2, 4000, 0, 0, 0);
3428 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3429 frequency_11(info) / 2, 4000, 4000, 0, 0);
3430
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003431 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003432 printk(RAM_SPEW, "[6dc] <= %x\n",
3433 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003434 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003435 } else
3436 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3437 info->delay46_ps[0], 0,
3438 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3440 frequency_11(info), 2500, 0, 0, 0);
3441 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3442 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003443 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003444 printk(RAM_SPEW, "[6e8] <= %x\n",
3445 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003446 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003447 } else
3448 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3449 info->delay46_ps[1], 0,
3450 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003451 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3452 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3453 470, 0);
3454 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3455 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3456 454, 459, 0);
3457 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3458 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3459 2588, 0);
3460 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3461 2405, 0);
3462 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3463 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3464 480, 0);
3465 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003466 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3467 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003468}
3469
3470static u16 get_max_timing(struct raminfo *info, int channel)
3471{
3472 int slot, rank, lane;
3473 u16 ret = 0;
3474
Felix Held04be2dd2018-07-29 04:53:22 +02003475 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003476 return 384;
3477
3478 if (info->revision < 8)
3479 return 256;
3480
3481 for (slot = 0; slot < NUM_SLOTS; slot++)
3482 for (rank = 0; rank < NUM_RANKS; rank++)
3483 if (info->populated_ranks[channel][slot][rank])
3484 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003485 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003486 get_timing_register_addr
3487 (lane, 0, slot,
3488 rank), 9));
3489 return ret;
3490}
3491
3492static void set_274265(struct raminfo *info)
3493{
3494 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3495 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3496 int delay_e_over_cycle_ps;
3497 int cycletime_ps;
3498 int channel;
3499
3500 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003501 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003502 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3503 cycletime_ps =
3504 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3505 delay_d_ps =
3506 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3507 - info->some_delay_3_ps_rounded + 200;
3508 if (!
3509 ((info->silicon_revision == 0
3510 || info->silicon_revision == 1)
3511 && (info->revision >= 8)))
3512 delay_d_ps += halfcycle_ps(info) * 2;
3513 delay_d_ps +=
3514 halfcycle_ps(info) * (!info->revision_flag_1 +
3515 info->some_delay_2_halfcycles_ceil +
3516 2 * info->some_delay_1_cycle_floor +
3517 info->clock_speed_index +
3518 2 * info->cas_latency - 7 + 11);
3519 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3520
Felix Held04be2dd2018-07-29 04:53:22 +02003521 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3522 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3523 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003524 delay_d_ps += 650;
3525 delay_c_ps = delay_d_ps + 1800;
3526 if (delay_c_ps <= delay_a_ps)
3527 delay_e_ps = 0;
3528 else
3529 delay_e_ps =
3530 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3531 cycletime_ps);
3532
3533 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3534 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3535 delay_f_cycles =
3536 div_roundup(2500 - delay_e_over_cycle_ps,
3537 2 * halfcycle_ps(info));
3538 if (delay_f_cycles > delay_e_cycles) {
3539 info->delay46_ps[channel] = delay_e_ps;
3540 delay_e_cycles = 0;
3541 } else {
3542 info->delay46_ps[channel] =
3543 delay_e_over_cycle_ps +
3544 2 * halfcycle_ps(info) * delay_f_cycles;
3545 delay_e_cycles -= delay_f_cycles;
3546 }
3547
3548 if (info->delay46_ps[channel] < 2500) {
3549 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003550 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003551 }
3552 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3553 if (delay_b_ps <= delay_a_ps)
3554 delay_b_ps = 0;
3555 else
3556 delay_b_ps -= delay_a_ps;
3557 info->delay54_ps[channel] =
3558 cycletime_ps * div_roundup(delay_b_ps,
3559 cycletime_ps) -
3560 2 * halfcycle_ps(info) * delay_e_cycles;
3561 if (info->delay54_ps[channel] < 2500)
3562 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003563 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003564 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3565 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003566 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003567 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003568 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003569 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3570 4 * halfcycle_ps(info)) - 6;
3571 MCHBAR32((channel << 10) + 0x274) =
3572 info->training.reg274265[channel][1] |
3573 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003574 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003575 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3576 4 * halfcycle_ps(info)) + 1;
3577 MCHBAR16((channel << 10) + 0x265) =
3578 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003580 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003581 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003582 else
Felix Held04be2dd2018-07-29 04:53:22 +02003583 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003584}
3585
3586static void restore_274265(struct raminfo *info)
3587{
3588 int channel;
3589
3590 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003591 MCHBAR32((channel << 10) + 0x274) =
3592 (info->cached_training->reg274265[channel][0] << 16) |
3593 info->cached_training->reg274265[channel][1];
3594 MCHBAR16((channel << 10) + 0x265) =
3595 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003596 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003597 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003598 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003599 else
Felix Held04be2dd2018-07-29 04:53:22 +02003600 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003601}
3602
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603static void dmi_setup(void)
3604{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003605 gav(DMIBAR8(0x254));
3606 DMIBAR8(0x254) = 0x1;
3607 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003608 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609
Angel Ponsd071c4d2020-09-14 23:51:35 +02003610 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611
3612 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3613 DEFAULT_GPIOBASE | 0x38);
3614 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3615}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003617void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003620 u16 ggc;
3621 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622
Felix Held04be2dd2018-07-29 04:53:22 +02003623 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3625 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003626 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003627 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629
3630 dmi_setup();
3631
Felix Held04be2dd2018-07-29 04:53:22 +02003632 MCHBAR16(0x1170) = 0xa880;
3633 MCHBAR8(0x11c1) = 0x1;
3634 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003635 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003637 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3638 /* 0 for 32MB */
3639 gfxsize = 0;
3640 }
3641
3642 ggc = 0xb00 | ((gfxsize + 5) << 4);
3643
Angel Pons16fe1e02020-07-22 16:12:33 +02003644 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645
3646 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003647 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648
3649 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003650 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003651 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003652 MCHBAR16_OR(0x2c30, 0x200);
3653 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003654 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003655 pci_read_config8(GMA, MSAC); // = 0x2
3656 pci_write_config8(GMA, MSAC, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003657 read8(DEFAULT_RCBA + 0x2318);
3658 write8(DEFAULT_RCBA + 0x2318, 0x47);
3659 read8(DEFAULT_RCBA + 0x2320);
3660 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661 }
3662
Felix Heldf83d80b2018-07-29 05:30:30 +02003663 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
Angel Pons16fe1e02020-07-22 16:12:33 +02003665 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003666 gav(read32(DEFAULT_RCBA + 0x3428));
3667 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003668}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003670void raminit(const int s3resume, const u8 *spd_addrmap)
3671{
Martin Roth468d02c2019-10-23 21:44:42 -06003672 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003673 int i;
3674 struct raminfo info;
3675 u8 x2ca8;
3676 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003677 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003678
Felix Held04be2dd2018-07-29 04:53:22 +02003679 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003680
3681 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3682
Angel Pons16fe1e02020-07-22 16:12:33 +02003683 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003684
3685 memset(&info, 0x5a, sizeof(info));
3686
3687 info.last_500_command[0] = 0;
3688 info.last_500_command[1] = 0;
3689
3690 info.fsb_frequency = 135 * 2;
3691 info.board_lane_delay[0] = 0x14;
3692 info.board_lane_delay[1] = 0x07;
3693 info.board_lane_delay[2] = 0x07;
3694 info.board_lane_delay[3] = 0x08;
3695 info.board_lane_delay[4] = 0x56;
3696 info.board_lane_delay[5] = 0x04;
3697 info.board_lane_delay[6] = 0x04;
3698 info.board_lane_delay[7] = 0x05;
3699 info.board_lane_delay[8] = 0x10;
3700
3701 info.training.reg_178 = 0;
3702 info.training.reg_10b = 0;
3703
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003704 info.memory_reserved_for_heci_mb = 0;
3705
3706 /* before SPD */
3707 timestamp_add_now(101);
3708
Felix Held29a9c072018-07-29 01:34:45 +02003709 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003710 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003711
3712 collect_system_info(&info);
3713
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003714 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3715
3716 info.use_ecc = 1;
3717 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003718 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003719 int v;
3720 int try;
3721 int addr;
3722 const u8 useful_addresses[] = {
3723 DEVICE_TYPE,
3724 MODULE_TYPE,
3725 DENSITY,
3726 RANKS_AND_DQ,
3727 MEMORY_BUS_WIDTH,
3728 TIMEBASE_DIVIDEND,
3729 TIMEBASE_DIVISOR,
3730 CYCLETIME,
3731 CAS_LATENCIES_LSB,
3732 CAS_LATENCIES_MSB,
3733 CAS_LATENCY_TIME,
3734 0x11, 0x12, 0x13, 0x14, 0x15,
3735 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3736 0x1c, 0x1d,
3737 THERMAL_AND_REFRESH,
3738 0x20,
3739 REFERENCE_RAW_CARD_USED,
3740 RANK1_ADDRESS_MAPPING,
3741 0x75, 0x76, 0x77, 0x78,
3742 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3743 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3744 0x85, 0x86, 0x87, 0x88,
3745 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3746 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3747 0x95
3748 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003749 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003750 continue;
3751 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003752 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003753 DEVICE_TYPE);
3754 if (v >= 0)
3755 break;
3756 }
3757 if (v < 0)
3758 continue;
3759 for (addr = 0;
3760 addr <
3761 sizeof(useful_addresses) /
3762 sizeof(useful_addresses[0]); addr++)
3763 gav(info.
3764 spd[channel][0][useful_addresses
3765 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003766 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003767 useful_addresses
3768 [addr]));
3769 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3770 die("Only DDR3 is supported");
3771
3772 v = info.spd[channel][0][RANKS_AND_DQ];
3773 info.populated_ranks[channel][0][0] = 1;
3774 info.populated_ranks[channel][0][1] =
3775 ((v >> 3) & 7);
3776 if (((v >> 3) & 7) > 1)
3777 die("At most 2 ranks are supported");
3778 if ((v & 7) == 0 || (v & 7) > 2)
3779 die("Only x8 and x16 modules are supported");
3780 if ((info.
3781 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3782 && (info.
3783 spd[channel][slot][MODULE_TYPE] & 0xF)
3784 != 3)
3785 die("Registered memory is not supported");
3786 info.is_x16_module[channel][0] = (v & 7) - 1;
3787 info.density[channel][slot] =
3788 info.spd[channel][slot][DENSITY] & 0xF;
3789 if (!
3790 (info.
3791 spd[channel][slot][MEMORY_BUS_WIDTH] &
3792 0x18))
3793 info.use_ecc = 0;
3794 }
3795
3796 gav(0x55);
3797
3798 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3799 int v = 0;
3800 for (slot = 0; slot < NUM_SLOTS; slot++)
3801 for (rank = 0; rank < NUM_RANKS; rank++)
3802 v |= info.
3803 populated_ranks[channel][slot][rank]
3804 << (2 * slot + rank);
3805 info.populated_ranks_mask[channel] = v;
3806 }
3807
3808 gav(0x55);
3809
Angel Pons16fe1e02020-07-22 16:12:33 +02003810 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003811 }
3812
3813 /* after SPD */
3814 timestamp_add_now(102);
3815
Felix Held04be2dd2018-07-29 04:53:22 +02003816 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003817
3818 collect_system_info(&info);
3819 calculate_timings(&info);
3820
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003821 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003822 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003823 if (x2ca8 == 0 && (reg8 & 0x80)) {
3824 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3825 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3826 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3827 */
3828
3829 /* Clear bit7. */
3830
3831 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3832 (reg8 & ~(1 << 7)));
3833
3834 printk(BIOS_INFO,
3835 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003836 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837 }
3838 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003839
3840 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003841 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3842 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003843
3844 compute_derived_timings(&info);
3845
3846 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003847 gav(MCHBAR8(0x164));
3848 MCHBAR8(0x164) = 0x26;
3849 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850 }
3851
Felix Held04be2dd2018-07-29 04:53:22 +02003852 MCHBAR32_OR(0x18b4, 0x210000);
3853 MCHBAR32_OR(0x1890, 0x2000000);
3854 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855
Angel Ponsa457e352020-07-22 18:17:33 +02003856 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3857 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003858
Felix Held04be2dd2018-07-29 04:53:22 +02003859 gav(MCHBAR16(0x2c10));
3860 MCHBAR16(0x2c10) = 0x412;
3861 gav(MCHBAR16(0x2c10));
3862 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863
Felix Held04be2dd2018-07-29 04:53:22 +02003864 gav(MCHBAR8(0x2ca8)); // !!!!
3865 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866
Angel Ponsa457e352020-07-22 18:17:33 +02003867 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3868 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003869 gav(MCHBAR32(0x1c04)); // !!!!
3870 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
3872 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003873 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874 }
3875
Felix Held04be2dd2018-07-29 04:53:22 +02003876 MCHBAR32(0x18d8) = 0x120000;
3877 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003878 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3879 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003880 MCHBAR32(0x18d8) = 0x40000;
3881 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003882 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3883 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003884 MCHBAR32(0x18d8) = 0x180000;
3885 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003886 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3887 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003888 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889
Felix Held04be2dd2018-07-29 04:53:22 +02003890 gav(MCHBAR32(0x18dc)); // !!!!
3891 MCHBAR32(0x18dc) = 0x3;
3892 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893
3894 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003895 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003896 }
3897
Felix Held04be2dd2018-07-29 04:53:22 +02003898 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003899 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003900 MCHBAR32(0x1a10) = 0x4200010e;
3901 MCHBAR32_OR(0x18b8, 0x200);
3902 gav(MCHBAR32(0x1918)); // !!!!
3903 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003904
Felix Held04be2dd2018-07-29 04:53:22 +02003905 gav(MCHBAR32(0x18b8)); // !!!!
3906 MCHBAR32(0x18b8) = 0xe00;
3907 gav(MCHBAR32(0x182c)); // !!!!
3908 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003909 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3910 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003911 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3912 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32_AND(0x18b4, 0xffff7fff);
3915 gav(MCHBAR32(0x1a68)); // !!!!
3916 MCHBAR32(0x1a68) = 0x343800;
3917 gav(MCHBAR32(0x1e68)); // !!!!
3918 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
3920 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003921 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922 }
3923
Angel Pons08143572020-07-22 17:47:06 +02003924 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3925 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3926 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3927 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3928 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003929 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3930 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003931 gav(MCHBAR32(0x1af0)); // !!!!
3932 gav(MCHBAR32(0x1af0)); // !!!!
3933 MCHBAR32(0x1af0) = 0x1f020003;
3934 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003936 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003938 }
3939
Felix Held04be2dd2018-07-29 04:53:22 +02003940 gav(MCHBAR32(0x1890)); // !!!!
3941 MCHBAR32(0x1890) = 0x80102;
3942 gav(MCHBAR32(0x18b4)); // !!!!
3943 MCHBAR32(0x18b4) = 0x216000;
3944 MCHBAR32(0x18a4) = 0x22222222;
3945 MCHBAR32(0x18a8) = 0x22222222;
3946 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003947
3948 udelay(1000);
3949
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003950 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003951
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003952 if (x2ca8 == 0) {
3953 int j;
3954 if (s3resume && info.cached_training) {
3955 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003956 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003957 info.cached_training->reg2ca9_bit0);
3958 for (i = 0; i < 2; i++)
3959 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003960 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003961 i, j, info.cached_training->reg274265[i][j]);
3962 } else {
3963 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003964 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003965 info.training.reg2ca9_bit0);
3966 for (i = 0; i < 2; i++)
3967 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003968 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003969 i, j, info.training.reg274265[i][j]);
3970 }
3971
3972 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003973
3974 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003975 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976 }
3977
3978 udelay(1000);
3979
3980 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003981 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003982 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003983 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3984 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3985 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003986
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003987 MCHBAR8(0x1150);
3988 MCHBAR8(0x1151);
3989 MCHBAR8(0x1022);
3990 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02003991 MCHBAR32(0x1300) = 0x60606060;
3992 MCHBAR32(0x1304) = 0x60606060;
3993 MCHBAR32(0x1308) = 0x78797a7b;
3994 MCHBAR32(0x130c) = 0x7c7d7e7f;
3995 MCHBAR32(0x1310) = 0x60606060;
3996 MCHBAR32(0x1314) = 0x60606060;
3997 MCHBAR32(0x1318) = 0x60606060;
3998 MCHBAR32(0x131c) = 0x60606060;
3999 MCHBAR32(0x1320) = 0x50515253;
4000 MCHBAR32(0x1324) = 0x54555657;
4001 MCHBAR32(0x1328) = 0x58595a5b;
4002 MCHBAR32(0x132c) = 0x5c5d5e5f;
4003 MCHBAR32(0x1330) = 0x40414243;
4004 MCHBAR32(0x1334) = 0x44454647;
4005 MCHBAR32(0x1338) = 0x48494a4b;
4006 MCHBAR32(0x133c) = 0x4c4d4e4f;
4007 MCHBAR32(0x1340) = 0x30313233;
4008 MCHBAR32(0x1344) = 0x34353637;
4009 MCHBAR32(0x1348) = 0x38393a3b;
4010 MCHBAR32(0x134c) = 0x3c3d3e3f;
4011 MCHBAR32(0x1350) = 0x20212223;
4012 MCHBAR32(0x1354) = 0x24252627;
4013 MCHBAR32(0x1358) = 0x28292a2b;
4014 MCHBAR32(0x135c) = 0x2c2d2e2f;
4015 MCHBAR32(0x1360) = 0x10111213;
4016 MCHBAR32(0x1364) = 0x14151617;
4017 MCHBAR32(0x1368) = 0x18191a1b;
4018 MCHBAR32(0x136c) = 0x1c1d1e1f;
4019 MCHBAR32(0x1370) = 0x10203;
4020 MCHBAR32(0x1374) = 0x4050607;
4021 MCHBAR32(0x1378) = 0x8090a0b;
4022 MCHBAR32(0x137c) = 0xc0d0e0f;
4023 MCHBAR8(0x11cc) = 0x4e;
4024 MCHBAR32(0x1110) = 0x73970404;
4025 MCHBAR32(0x1114) = 0x72960404;
4026 MCHBAR32(0x1118) = 0x6f950404;
4027 MCHBAR32(0x111c) = 0x6d940404;
4028 MCHBAR32(0x1120) = 0x6a930404;
4029 MCHBAR32(0x1124) = 0x68a41404;
4030 MCHBAR32(0x1128) = 0x66a21404;
4031 MCHBAR32(0x112c) = 0x63a01404;
4032 MCHBAR32(0x1130) = 0x609e1404;
4033 MCHBAR32(0x1134) = 0x5f9c1404;
4034 MCHBAR32(0x1138) = 0x5c961404;
4035 MCHBAR32(0x113c) = 0x58a02404;
4036 MCHBAR32(0x1140) = 0x54942404;
4037 MCHBAR32(0x1190) = 0x900080a;
4038 MCHBAR16(0x11c0) = 0xc40b;
4039 MCHBAR16(0x11c2) = 0x303;
4040 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004041 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004042 MCHBAR32(0x11b8) = 0x70c3000;
4043 MCHBAR8(0x11ec) = 0xa;
4044 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004045 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004046 MCHBAR16(0x11ca) = 0xfa;
4047 MCHBAR32(0x11e4) = 0x4e20;
4048 MCHBAR8(0x11bc) = 0xf;
4049 MCHBAR16(0x11da) = 0x19;
4050 MCHBAR16(0x11ba) = 0x470c;
4051 MCHBAR32(0x1680) = 0xe6ffe4ff;
4052 MCHBAR32(0x1684) = 0xdeffdaff;
4053 MCHBAR32(0x1688) = 0xd4ffd0ff;
4054 MCHBAR32(0x168c) = 0xccffc6ff;
4055 MCHBAR32(0x1690) = 0xc0ffbeff;
4056 MCHBAR32(0x1694) = 0xb8ffb0ff;
4057 MCHBAR32(0x1698) = 0xa8ff0000;
4058 MCHBAR32(0x169c) = 0xc00;
4059 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004060 }
4061
Felix Held04be2dd2018-07-29 04:53:22 +02004062 MCHBAR32(0x124c) = 0x15040d00;
4063 MCHBAR32(0x1250) = 0x7f0000;
4064 MCHBAR32(0x1254) = 0x1e220004;
4065 MCHBAR32(0x1258) = 0x4000004;
4066 MCHBAR32(0x1278) = 0x0;
4067 MCHBAR32(0x125c) = 0x0;
4068 MCHBAR32(0x1260) = 0x0;
4069 MCHBAR32(0x1264) = 0x0;
4070 MCHBAR32(0x1268) = 0x0;
4071 MCHBAR32(0x126c) = 0x0;
4072 MCHBAR32(0x1270) = 0x0;
4073 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004074 }
4075
4076 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004077 MCHBAR16(0x1214) = 0x320;
4078 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004079 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4080 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004081 MCHBAR32(0x1400) = 0x13040020;
4082 MCHBAR32(0x1404) = 0xe090120;
4083 MCHBAR32(0x1408) = 0x5120220;
4084 MCHBAR32(0x140c) = 0x5120330;
4085 MCHBAR32(0x1410) = 0xe090220;
4086 MCHBAR32(0x1414) = 0x1010001;
4087 MCHBAR32(0x1418) = 0x1110000;
4088 MCHBAR32(0x141c) = 0x9020020;
4089 MCHBAR32(0x1420) = 0xd090220;
4090 MCHBAR32(0x1424) = 0x2090220;
4091 MCHBAR32(0x1428) = 0x2090330;
4092 MCHBAR32(0x142c) = 0xd090220;
4093 MCHBAR32(0x1430) = 0x1010001;
4094 MCHBAR32(0x1434) = 0x1110000;
4095 MCHBAR32(0x1438) = 0x11040020;
4096 MCHBAR32(0x143c) = 0x4030220;
4097 MCHBAR32(0x1440) = 0x1060220;
4098 MCHBAR32(0x1444) = 0x1060330;
4099 MCHBAR32(0x1448) = 0x4030220;
4100 MCHBAR32(0x144c) = 0x1010001;
4101 MCHBAR32(0x1450) = 0x1110000;
4102 MCHBAR32(0x1454) = 0x4010020;
4103 MCHBAR32(0x1458) = 0xb090220;
4104 MCHBAR32(0x145c) = 0x1090220;
4105 MCHBAR32(0x1460) = 0x1090330;
4106 MCHBAR32(0x1464) = 0xb090220;
4107 MCHBAR32(0x1468) = 0x1010001;
4108 MCHBAR32(0x146c) = 0x1110000;
4109 MCHBAR32(0x1470) = 0xf040020;
4110 MCHBAR32(0x1474) = 0xa090220;
4111 MCHBAR32(0x1478) = 0x1120220;
4112 MCHBAR32(0x147c) = 0x1120330;
4113 MCHBAR32(0x1480) = 0xa090220;
4114 MCHBAR32(0x1484) = 0x1010001;
4115 MCHBAR32(0x1488) = 0x1110000;
4116 MCHBAR32(0x148c) = 0x7020020;
4117 MCHBAR32(0x1490) = 0x1010220;
4118 MCHBAR32(0x1494) = 0x10210;
4119 MCHBAR32(0x1498) = 0x10320;
4120 MCHBAR32(0x149c) = 0x1010220;
4121 MCHBAR32(0x14a0) = 0x1010001;
4122 MCHBAR32(0x14a4) = 0x1110000;
4123 MCHBAR32(0x14a8) = 0xd040020;
4124 MCHBAR32(0x14ac) = 0x8090220;
4125 MCHBAR32(0x14b0) = 0x1111310;
4126 MCHBAR32(0x14b4) = 0x1111420;
4127 MCHBAR32(0x14b8) = 0x8090220;
4128 MCHBAR32(0x14bc) = 0x1010001;
4129 MCHBAR32(0x14c0) = 0x1110000;
4130 MCHBAR32(0x14c4) = 0x3010020;
4131 MCHBAR32(0x14c8) = 0x7090220;
4132 MCHBAR32(0x14cc) = 0x1081310;
4133 MCHBAR32(0x14d0) = 0x1081420;
4134 MCHBAR32(0x14d4) = 0x7090220;
4135 MCHBAR32(0x14d8) = 0x1010001;
4136 MCHBAR32(0x14dc) = 0x1110000;
4137 MCHBAR32(0x14e0) = 0xb040020;
4138 MCHBAR32(0x14e4) = 0x2030220;
4139 MCHBAR32(0x14e8) = 0x1051310;
4140 MCHBAR32(0x14ec) = 0x1051420;
4141 MCHBAR32(0x14f0) = 0x2030220;
4142 MCHBAR32(0x14f4) = 0x1010001;
4143 MCHBAR32(0x14f8) = 0x1110000;
4144 MCHBAR32(0x14fc) = 0x5020020;
4145 MCHBAR32(0x1500) = 0x5090220;
4146 MCHBAR32(0x1504) = 0x2071310;
4147 MCHBAR32(0x1508) = 0x2071420;
4148 MCHBAR32(0x150c) = 0x5090220;
4149 MCHBAR32(0x1510) = 0x1010001;
4150 MCHBAR32(0x1514) = 0x1110000;
4151 MCHBAR32(0x1518) = 0x7040120;
4152 MCHBAR32(0x151c) = 0x2090220;
4153 MCHBAR32(0x1520) = 0x70b1210;
4154 MCHBAR32(0x1524) = 0x70b1310;
4155 MCHBAR32(0x1528) = 0x2090220;
4156 MCHBAR32(0x152c) = 0x1010001;
4157 MCHBAR32(0x1530) = 0x1110000;
4158 MCHBAR32(0x1534) = 0x1010110;
4159 MCHBAR32(0x1538) = 0x1081310;
4160 MCHBAR32(0x153c) = 0x5041200;
4161 MCHBAR32(0x1540) = 0x5041310;
4162 MCHBAR32(0x1544) = 0x1081310;
4163 MCHBAR32(0x1548) = 0x1010001;
4164 MCHBAR32(0x154c) = 0x1110000;
4165 MCHBAR32(0x1550) = 0x1040120;
4166 MCHBAR32(0x1554) = 0x4051210;
4167 MCHBAR32(0x1558) = 0xd051200;
4168 MCHBAR32(0x155c) = 0xd051200;
4169 MCHBAR32(0x1560) = 0x4051210;
4170 MCHBAR32(0x1564) = 0x1010001;
4171 MCHBAR32(0x1568) = 0x1110000;
4172 MCHBAR16(0x1222) = 0x220a;
4173 MCHBAR16(0x123c) = 0x1fc0;
4174 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004175 }
4176
Felix Heldf83d80b2018-07-29 05:30:30 +02004177 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004178 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004179 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004180
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004181 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004182
4183 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004184 MCHBAR8_AND(0x2ca8, ~3);
4185 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004186 /* This issues a CPU reset without resetting the platform */
4187 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004188 /* Write back the S3 state to PM1_CNT to let the reset CPU
4189 know it also needs to take the s3 path. */
4190 if (s3resume)
4191 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4192 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004193 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004194 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004195 }
4196
Felix Held04be2dd2018-07-29 04:53:22 +02004197 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004198 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004199 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004200 MCHBAR16(0x2c20); // !!!!
4201 MCHBAR16(0x2c10); // !!!!
4202 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004203 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004204 udelay(1000);
4205 write_1d0(0, 0x33d, 0, 0);
4206 write_500(&info, 0, 0, 0xb61, 0, 0);
4207 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004208 MCHBAR32(0x1a30) = 0x0;
4209 MCHBAR32(0x1a34) = 0x0;
4210 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4211 (info.populated_ranks[0][0][0] * 0xa0);
4212 MCHBAR16(0x616) = 0x26a;
4213 MCHBAR32(0x134) = 0x856000;
4214 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004215 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4216 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004217 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004218 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4219 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004220 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004221 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004222 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4223 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004224 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4225 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4226 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4227 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4228 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4229 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4230 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4231 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4232 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4233 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004234 }
4235
4236 write_1d0(0x4, 0x151, 4, 1);
4237 write_1d0(0, 0x142, 3, 1);
4238 rdmsr(0x1ac); // !!!!
4239 write_500(&info, 1, 1, 0x6b3, 4, 1);
4240 write_500(&info, 1, 1, 0x6cf, 4, 1);
4241
4242 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4243
4244 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4245 populated_ranks[0]
4246 [0][0]) << 0),
4247 0x1d1, 3, 1);
4248 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004249 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4250 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251 }
4252
4253 set_334(0);
4254
4255 program_base_timings(&info);
4256
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004258
4259 write_1d0(0x2, 0x1d5, 2, 1);
4260 write_1d0(0x20, 0x166, 7, 1);
4261 write_1d0(0x0, 0xeb, 3, 1);
4262 write_1d0(0x0, 0xf3, 6, 1);
4263
4264 for (channel = 0; channel < NUM_CHANNELS; channel++)
4265 for (lane = 0; lane < 9; lane++) {
4266 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4267 u8 a;
4268 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4269 write_500(&info, channel, a, addr, 6, 1);
4270 }
4271
4272 udelay(1000);
4273
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004274 if (s3resume) {
4275 if (info.cached_training == NULL) {
4276 u32 reg32;
4277 printk(BIOS_ERR,
4278 "Couldn't find training data. Rebooting\n");
4279 reg32 = inl(DEFAULT_PMBASE + 0x04);
4280 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004281 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004282 }
4283 int tm;
4284 info.training = *info.cached_training;
4285 for (tm = 0; tm < 4; tm++)
4286 for (channel = 0; channel < NUM_CHANNELS; channel++)
4287 for (slot = 0; slot < NUM_SLOTS; slot++)
4288 for (rank = 0; rank < NUM_RANKS; rank++)
4289 for (lane = 0; lane < 9; lane++)
4290 write_500(&info,
4291 channel,
4292 info.training.
4293 lane_timings
4294 [tm][channel]
4295 [slot][rank]
4296 [lane],
4297 get_timing_register_addr
4298 (lane, tm,
4299 slot, rank),
4300 9, 0);
4301 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4302 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4303 }
4304
Felix Heldf83d80b2018-07-29 05:30:30 +02004305 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004306 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004307 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004308 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004309
4310 program_board_delay(&info);
4311
Felix Held04be2dd2018-07-29 04:53:22 +02004312 MCHBAR8(0x5ff) = 0x0;
4313 MCHBAR8(0x5ff) = 0x80;
4314 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004315
Felix Held04be2dd2018-07-29 04:53:22 +02004316 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004317 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004318 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004319 gav(read_1d0(0x14b, 7)); // = 0x81023100
4320 write_1d0(0x30, 0x14b, 7, 1);
4321 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4322 write_1d0(7, 0xd6, 6, 1);
4323 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4324 write_1d0(7, 0x328, 6, 1);
4325
4326 for (channel = 0; channel < NUM_CHANNELS; channel++)
4327 set_4cf(&info, channel,
4328 info.populated_ranks[channel][0][0] ? 8 : 0);
4329
4330 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4331 write_1d0(2, 0x116, 4, 1);
4332 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4333 write_1d0(0, 0xae, 6, 1);
4334 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4335 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004336 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4337 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004338 MCHBAR32_AND(0x140, ~0x07000000);
4339 MCHBAR32_AND(0x138, ~0x07000000);
4340 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004341 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004342 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004343 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004344
4345 {
4346 u32 t;
4347 u8 val_a1;
4348 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4349 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4350 rmw_1d0(0x320, 0x07,
4351 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4352 rmw_1d0(0x14b, 0x78,
4353 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4354 4), 7,
4355 1);
4356 rmw_1d0(0xce, 0x38,
4357 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4358 4), 6,
4359 1);
4360 }
4361
4362 for (channel = 0; channel < NUM_CHANNELS; channel++)
4363 set_4cf(&info, channel,
4364 info.populated_ranks[channel][0][0] ? 9 : 1);
4365
4366 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004367 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004368 write_1d0(2, 0xae, 6, 1);
4369 write_1d0(2, 0x300, 6, 1);
4370 write_1d0(2, 0x121, 3, 1);
4371 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4372 write_1d0(4, 0xd6, 6, 1);
4373 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4374 write_1d0(4, 0x328, 6, 1);
4375
4376 for (channel = 0; channel < NUM_CHANNELS; channel++)
4377 set_4cf(&info, channel,
4378 info.populated_ranks[channel][0][0] ? 9 : 0);
4379
Felix Held04be2dd2018-07-29 04:53:22 +02004380 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4381 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004382 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004383 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004384 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4385 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4386 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4387 write_1d0(0, 0x21c, 6, 1);
4388 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4389 write_1d0(0x35, 0x14b, 7, 1);
4390
4391 for (channel = 0; channel < NUM_CHANNELS; channel++)
4392 set_4cf(&info, channel,
4393 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4394
4395 set_334(1);
4396
Felix Held04be2dd2018-07-29 04:53:22 +02004397 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004398
4399 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4400 write_500(&info, channel,
4401 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4402 1);
4403 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4404 }
Felix Held04be2dd2018-07-29 04:53:22 +02004405 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4406 MCHBAR16(0x6c0) = 0x14a0;
4407 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4408 MCHBAR16(0x232) = 0x8;
4409 /* 0x40004 or 0 depending on ? */
4410 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4411 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4412 MCHBAR32(0x128) = 0x2150d05;
4413 MCHBAR8(0x12c) = 0x1f;
4414 MCHBAR8(0x12d) = 0x56;
4415 MCHBAR8(0x12e) = 0x31;
4416 MCHBAR8(0x12f) = 0x0;
4417 MCHBAR8(0x271) = 0x2;
4418 MCHBAR8(0x671) = 0x2;
4419 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004420 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004421 MCHBAR32(0x294 + (channel << 10)) =
4422 (info.populated_ranks_mask[channel] & 3) << 16;
4423 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4424 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004425 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004426 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4427 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004428
4429 if (!s3resume)
4430 jedec_init(&info);
4431
4432 int totalrank = 0;
4433 for (channel = 0; channel < NUM_CHANNELS; channel++)
4434 for (slot = 0; slot < NUM_SLOTS; slot++)
4435 for (rank = 0; rank < NUM_RANKS; rank++)
4436 if (info.populated_ranks[channel][slot][rank]) {
4437 jedec_read(&info, channel, slot, rank,
4438 totalrank, 0xa, 0x400);
4439 totalrank++;
4440 }
4441
Felix Held04be2dd2018-07-29 04:53:22 +02004442 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004443
Felix Heldf83d80b2018-07-29 05:30:30 +02004444 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4445 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004446
4447 if (!s3resume) {
4448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004449 MCHBAR32(0x294 + (channel << 10)) =
4450 (info.populated_ranks_mask[channel] & 3) << 16;
4451 MCHBAR16(0x298 + (channel << 10)) =
4452 info.populated_ranks[channel][0][0] |
4453 (info.populated_ranks[channel][0][1] << 5);
4454 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004455 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004456 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457
4458 {
4459 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004460 a = MCHBAR8(0x243);
4461 b = MCHBAR8(0x643);
4462 MCHBAR8(0x243) = a | 2;
4463 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004464 }
4465
4466 write_1d0(7, 0x19b, 3, 1);
4467 write_1d0(7, 0x1c0, 3, 1);
4468 write_1d0(4, 0x1c6, 4, 1);
4469 write_1d0(4, 0x1cc, 4, 1);
4470 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4471 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004472 MCHBAR32(0x584) = 0xfffff;
4473 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004474
4475 for (channel = 0; channel < NUM_CHANNELS; channel++)
4476 for (slot = 0; slot < NUM_SLOTS; slot++)
4477 for (rank = 0; rank < NUM_RANKS; rank++)
4478 if (info.
4479 populated_ranks[channel][slot]
4480 [rank])
4481 config_rank(&info, s3resume,
4482 channel, slot,
4483 rank);
4484
Felix Held04be2dd2018-07-29 04:53:22 +02004485 MCHBAR8(0x243) = 0x1;
4486 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004487 }
4488
4489 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004490 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004491 write_26c(0, 0x820);
4492 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004493 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004494 /* end */
4495
4496 if (s3resume) {
4497 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR32(0x294 + (channel << 10)) =
4499 (info.populated_ranks_mask[channel] & 3) << 16;
4500 MCHBAR16(0x298 + (channel << 10)) =
4501 info.populated_ranks[channel][0][0] |
4502 (info.populated_ranks[channel][0][1] << 5);
4503 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004505 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506 }
4507
Felix Held04be2dd2018-07-29 04:53:22 +02004508 MCHBAR32_AND(0xfa4, ~0x01000002);
4509 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511 /* Before training. */
4512 timestamp_add_now(103);
4513
4514 if (!s3resume)
4515 ram_training(&info);
4516
4517 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004518 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519
4520 dump_timings(&info);
4521
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522 program_modules_memory_map(&info, 0);
4523 program_total_memory_map(&info);
4524
4525 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004526 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004527 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004528 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004530 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 else
Felix Held04be2dd2018-07-29 04:53:22 +02004532 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR32_AND(0xfac, ~0x80000000);
4535 MCHBAR32(0xfb4) = 0x4800;
4536 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4537 MCHBAR32(0xe94) = 0x7ffff;
4538 MCHBAR32(0xfc0) = 0x80002040;
4539 MCHBAR32(0xfc4) = 0x701246;
4540 MCHBAR8_AND(0xfc8, ~0x70);
4541 MCHBAR32_OR(0xe5c, 0x1000000);
4542 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4543 MCHBAR32(0x50) = 0x700b0;
4544 MCHBAR32(0x3c) = 0x10;
4545 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4546 MCHBAR8_OR(0xff4, 0x2);
4547 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004548
Felix Held04be2dd2018-07-29 04:53:22 +02004549 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4550 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4551 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004552
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004553 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4554 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4555 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557 {
4558 u32 eax;
4559
4560 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004561 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4562 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4563 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004564 }
4565
4566 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004567 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004569 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 else
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572
Felix Held04be2dd2018-07-29 04:53:22 +02004573 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574
Felix Held04be2dd2018-07-29 04:53:22 +02004575 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 else
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 }
4581
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583
4584 {
4585 u8 al;
4586 al = 0xd;
4587 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4588 al += 2;
4589 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004591 }
4592
4593 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004594 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4595 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4596 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4597 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598 }
4599 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004600 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004601 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004602 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004603 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004604 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004605 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004606 MCHBAR8_OR(0x1210, 2);
4607 MCHBAR32(0x1200) = 0x8800440;
4608 MCHBAR32(0x1204) = 0x53ff0453;
4609 MCHBAR32(0x1208) = 0x19002043;
4610 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004611
4612 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004613 MCHBAR16(0x1214) = 0x220;
4614 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004615 }
4616
Felix Held04be2dd2018-07-29 04:53:22 +02004617 MCHBAR8_OR(0x1214, 0x4);
4618 MCHBAR8(0x120c) = 0x1;
4619 MCHBAR8(0x1218) = 0x3;
4620 MCHBAR8(0x121a) = 0x3;
4621 MCHBAR8(0x121c) = 0x3;
4622 MCHBAR16(0xc14) = 0x0;
4623 MCHBAR16(0xc20) = 0x0;
4624 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004625
4626 /* revision dependent here. */
4627
Felix Held04be2dd2018-07-29 04:53:22 +02004628 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004629
4630 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004631 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR16_OR(0x1230, 0x8000);
4634 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
4636 u8 bl, ebpb;
4637 u16 reg_1020;
4638
Felix Held04be2dd2018-07-29 04:53:22 +02004639 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4640 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR32(0x1000) = 0x100;
4643 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644
4645 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647 bl = reg_1020 >> 8;
4648 ebpb = reg_1020 & 0xff;
4649 } else {
4650 ebpb = 0;
4651 bl = 8;
4652 }
4653
4654 rdmsr(0x1a2);
4655
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004664 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4665 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004666 }
4667
4668 setup_heci_uma(&info);
4669
4670 if (info.uma_enabled) {
4671 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004672 MCHBAR32_OR(0x11b0, 0x4000);
4673 MCHBAR32_OR(0x11b4, 0x4000);
4674 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675
Felix Held04be2dd2018-07-29 04:53:22 +02004676 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4677 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4678 MCHBAR16_OR(0x1170, 0x1000);
4679
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004681
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004683 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004684 ;
4685 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004686 }
4687
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004688 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4689 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693 udelay(1000);
4694 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004695 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4696
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697 if (!s3resume)
4698 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004699 if (s3resume && cbmem_wasnot_inited) {
4700 u32 reg32;
4701 printk(BIOS_ERR, "Failed S3 resume.\n");
4702 ram_check(0x100000, 0x200000);
4703
4704 /* Clear SLP_TYPE. */
4705 reg32 = inl(DEFAULT_PMBASE + 0x04);
4706 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4707
4708 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004709 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004710 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711}