blob: 7263e2e84680512f56b24bca462ef3fe2be1ad41 [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 Ponsd02f3302020-09-14 18:42:12 +020064#define MRC_CACHE_VERSION 2
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
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100195 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600196 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100197
198 struct ram_training training;
199 u32 last_500_command[2];
200
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100201 u32 delay46_ps[2];
202 u32 delay54_ps[2];
203 u8 revision_flag_1;
204 u8 some_delay_1_cycle_floor;
205 u8 some_delay_2_halfcycles_ceil;
206 u8 some_delay_3_ps_rounded;
207
208 const struct ram_training *cached_training;
209};
210
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200211/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100212timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200213
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214static void
215write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
216 int flag);
217
218/* OK */
219static u16
220read_500(struct raminfo *info, int channel, u16 addr, int split)
221{
222 u32 val;
223 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200224 MCHBAR32(0x500 + (channel << 10)) = 0;
225 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
226 ;
227 MCHBAR32(0x500 + (channel << 10)) =
228 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
229 + 0xb88 - addr);
230 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
231 ;
232 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100233 return val & ((1 << split) - 1);
234}
235
236/* OK */
237static void
238write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
239 int flag)
240{
241 if (info->last_500_command[channel] == 0x80000000) {
242 info->last_500_command[channel] = 0x40000000;
243 write_500(info, channel, 0, 0xb61, 0, 0);
244 }
Felix Held04be2dd2018-07-29 04:53:22 +0200245 MCHBAR32(0x500 + (channel << 10)) = 0;
246 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
247 ;
248 MCHBAR32(0x504 + (channel << 10)) =
249 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
250 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200251 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200252 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100253}
254
255static int rw_test(int rank)
256{
257 const u32 mask = 0xf00fc33c;
258 int ok = 0xff;
259 int i;
260 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800261 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100262 sfence();
263 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800264 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100265 sfence();
266 for (i = 0; i < 32; i++) {
267 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800268 write32p((rank << 28) | (i << 3), pat);
269 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270 }
271 sfence();
272 for (i = 0; i < 32; i++) {
273 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
274 int j;
275 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100277 for (j = 0; j < 4; j++)
278 if (((val >> (j * 8)) & 0xff) != pat)
279 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800280 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100281 for (j = 0; j < 4; j++)
282 if (((val >> (j * 8)) & 0xff) != pat)
283 ok &= ~(16 << j);
284 }
285 sfence();
286 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800287 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288 sfence();
289 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800290 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291
292 return ok;
293}
294
295static void
296program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
297{
298 int lane;
299 for (lane = 0; lane < 8; lane++) {
300 write_500(info, channel,
301 base +
302 info->training.
303 lane_timings[2][channel][slot][rank][lane],
304 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
305 write_500(info, channel,
306 base +
307 info->training.
308 lane_timings[3][channel][slot][rank][lane],
309 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
310 }
311}
312
313static void write_26c(int channel, u16 si)
314{
Felix Held04be2dd2018-07-29 04:53:22 +0200315 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
316 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
317 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100318}
319
320static u32 get_580(int channel, u8 addr)
321{
322 u32 ret;
323 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200324 MCHBAR8(0x5ff) = 0x0;
325 MCHBAR8(0x5ff) = 0x80;
326 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
327 MCHBAR8_OR(0x580 + (channel << 10), 1);
328 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
329 ;
330 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100331 return ret;
332}
333
334const int cached_config = 0;
335
336#define NUM_CHANNELS 2
337#define NUM_SLOTS 2
338#define NUM_RANKS 2
339#define RANK_SHIFT 28
340#define CHANNEL_SHIFT 10
341
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100342static void seq9(struct raminfo *info, int channel, int slot, int rank)
343{
344 int i, lane;
345
346 for (i = 0; i < 2; i++)
347 for (lane = 0; lane < 8; lane++)
348 write_500(info, channel,
349 info->training.lane_timings[i +
350 1][channel][slot]
351 [rank][lane], get_timing_register_addr(lane,
352 i + 1,
353 slot,
354 rank),
355 9, 0);
356
357 write_1d0(1, 0x103, 6, 1);
358 for (lane = 0; lane < 8; lane++)
359 write_500(info, channel,
360 info->training.
361 lane_timings[0][channel][slot][rank][lane],
362 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
363
364 for (i = 0; i < 2; i++) {
365 for (lane = 0; lane < 8; lane++)
366 write_500(info, channel,
367 info->training.lane_timings[i +
368 1][channel][slot]
369 [rank][lane], get_timing_register_addr(lane,
370 i + 1,
371 slot,
372 rank),
373 9, 0);
374 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
375 }
376
377 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200378 MCHBAR8(0x5ff) = 0x0;
379 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100380 write_1d0(0x2, 0x142, 3, 1);
381 for (lane = 0; lane < 8; lane++) {
382 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
383 info->training.lane_timings[2][channel][slot][rank][lane] =
384 read_500(info, channel,
385 get_timing_register_addr(lane, 2, slot, rank), 9);
386 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
387 info->training.lane_timings[3][channel][slot][rank][lane] =
388 info->training.lane_timings[2][channel][slot][rank][lane] +
389 0x20;
390 }
391}
392
393static int count_ranks_in_channel(struct raminfo *info, int channel)
394{
395 int slot, rank;
396 int res = 0;
397 for (slot = 0; slot < NUM_SLOTS; slot++)
398 for (rank = 0; rank < NUM_SLOTS; rank++)
399 res += info->populated_ranks[channel][slot][rank];
400 return res;
401}
402
403static void
404config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
405{
406 int add;
407
408 write_1d0(0, 0x178, 7, 1);
409 seq9(info, channel, slot, rank);
410 program_timings(info, 0x80, channel, slot, rank);
411
412 if (channel == 0)
413 add = count_ranks_in_channel(info, 1);
414 else
415 add = 0;
416 if (!s3resume)
417 gav(rw_test(rank + add));
418 program_timings(info, 0x00, channel, slot, rank);
419 if (!s3resume)
420 gav(rw_test(rank + add));
421 if (!s3resume)
422 gav(rw_test(rank + add));
423 write_1d0(0, 0x142, 3, 1);
424 write_1d0(0, 0x103, 6, 1);
425
426 gav(get_580(channel, 0xc | (rank << 5)));
427 gav(read_1d0(0x142, 3));
428
Felix Held04be2dd2018-07-29 04:53:22 +0200429 MCHBAR8(0x5ff) = 0x0;
430 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100431}
432
433static void set_4cf(struct raminfo *info, int channel, u8 val)
434{
435 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
436 write_500(info, channel, val, 0x4cf, 4, 1);
437 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
438 write_500(info, channel, val, 0x659, 4, 1);
439 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
440 write_500(info, channel, val, 0x697, 4, 1);
441}
442
443static void set_334(int zero)
444{
445 int j, k, channel;
446 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
447 u32 vd8[2][16];
448
449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
450 for (j = 0; j < 4; j++) {
451 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
452 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
453 u16 c;
454 if ((j == 0 || j == 3) && zero)
455 c = 0;
456 else if (j == 3)
457 c = 0x5f;
458 else
459 c = 0x5f5f;
460
461 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200462 MCHBAR32(0x138 + 8 * k) =
463 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100464 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200465 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100466 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200467 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100468 }
469
Felix Held22ca8cb2018-07-29 05:09:44 +0200470 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
471 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200472 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
473 zero ? 0 : (0x18191819 & lmask);
474 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
475 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
476 zero ? 0 : (a & lmask);
477 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
478 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100479 }
480 }
481
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32_OR(0x130, 1);
483 while (MCHBAR8(0x130) & 1)
484 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485}
486
487static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
488{
489 u32 v;
490 v = read_1d0(addr, split);
491 write_1d0((v & and) | or, addr, split, flag);
492}
493
494static int find_highest_bit_set(u16 val)
495{
496 int i;
497 for (i = 15; i >= 0; i--)
498 if (val & (1 << i))
499 return i;
500 return -1;
501}
502
503static int find_lowest_bit_set32(u32 val)
504{
505 int i;
506 for (i = 0; i < 32; i++)
507 if (val & (1 << i))
508 return i;
509 return -1;
510}
511
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100512enum {
513 DEVICE_TYPE = 2,
514 MODULE_TYPE = 3,
515 DENSITY = 4,
516 RANKS_AND_DQ = 7,
517 MEMORY_BUS_WIDTH = 8,
518 TIMEBASE_DIVIDEND = 10,
519 TIMEBASE_DIVISOR = 11,
520 CYCLETIME = 12,
521
522 CAS_LATENCIES_LSB = 14,
523 CAS_LATENCIES_MSB = 15,
524 CAS_LATENCY_TIME = 16,
525 THERMAL_AND_REFRESH = 31,
526 REFERENCE_RAW_CARD_USED = 62,
527 RANK1_ADDRESS_MAPPING = 63
528};
529
530static void calculate_timings(struct raminfo *info)
531{
Martin Roth468d02c2019-10-23 21:44:42 -0600532 unsigned int cycletime;
533 unsigned int cas_latency_time;
534 unsigned int supported_cas_latencies;
535 unsigned int channel, slot;
536 unsigned int clock_speed_index;
537 unsigned int min_cas_latency;
538 unsigned int cas_latency;
539 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100540
541 /* Find common CAS latency */
542 supported_cas_latencies = 0x3fe;
543 for (channel = 0; channel < NUM_CHANNELS; channel++)
544 for (slot = 0; slot < NUM_SLOTS; slot++)
545 if (info->populated_ranks[channel][slot][0])
546 supported_cas_latencies &=
547 2 *
548 (info->
549 spd[channel][slot][CAS_LATENCIES_LSB] |
550 (info->
551 spd[channel][slot][CAS_LATENCIES_MSB] <<
552 8));
553
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100554 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100555
556 cycletime = min_cycletime[max_clock_index];
557 cas_latency_time = min_cas_latency_time[max_clock_index];
558
559 for (channel = 0; channel < NUM_CHANNELS; channel++)
560 for (slot = 0; slot < NUM_SLOTS; slot++)
561 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600562 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100563 timebase =
564 1000 *
565 info->
566 spd[channel][slot][TIMEBASE_DIVIDEND] /
567 info->spd[channel][slot][TIMEBASE_DIVISOR];
568 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100569 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100570 timebase *
571 info->spd[channel][slot][CYCLETIME]);
572 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100573 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100574 timebase *
575 info->
576 spd[channel][slot][CAS_LATENCY_TIME]);
577 }
Jacob Garber3c193822019-06-10 18:23:32 -0600578 if (cycletime > min_cycletime[0])
579 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100580 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
581 if (cycletime == min_cycletime[clock_speed_index])
582 break;
583 if (cycletime > min_cycletime[clock_speed_index]) {
584 clock_speed_index--;
585 cycletime = min_cycletime[clock_speed_index];
586 break;
587 }
588 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100589 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100590 cas_latency = 0;
591 while (supported_cas_latencies) {
592 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
593 if (cas_latency <= min_cas_latency)
594 break;
595 supported_cas_latencies &=
596 ~(1 << find_highest_bit_set(supported_cas_latencies));
597 }
598
599 if (cas_latency != min_cas_latency && clock_speed_index)
600 clock_speed_index--;
601
602 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
603 die("Couldn't configure DRAM");
604 info->clock_speed_index = clock_speed_index;
605 info->cas_latency = cas_latency;
606}
607
608static void program_base_timings(struct raminfo *info)
609{
Martin Roth468d02c2019-10-23 21:44:42 -0600610 unsigned int channel;
611 unsigned int slot, rank, lane;
612 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100613 int i;
614
615 extended_silicon_revision = info->silicon_revision;
616 if (info->silicon_revision == 0)
617 for (channel = 0; channel < NUM_CHANNELS; channel++)
618 for (slot = 0; slot < NUM_SLOTS; slot++)
619 if ((info->
620 spd[channel][slot][MODULE_TYPE] & 0xF) ==
621 3)
622 extended_silicon_revision = 4;
623
624 for (channel = 0; channel < NUM_CHANNELS; channel++) {
625 for (slot = 0; slot < NUM_SLOTS; slot++)
626 for (rank = 0; rank < NUM_SLOTS; rank++) {
627 int card_timing_2;
628 if (!info->populated_ranks[channel][slot][rank])
629 continue;
630
631 for (lane = 0; lane < 9; lane++) {
632 int tm_reg;
633 int card_timing;
634
635 card_timing = 0;
636 if ((info->
637 spd[channel][slot][MODULE_TYPE] &
638 0xF) == 3) {
639 int reference_card;
640 reference_card =
641 info->
642 spd[channel][slot]
643 [REFERENCE_RAW_CARD_USED] &
644 0x1f;
645 if (reference_card == 3)
646 card_timing =
647 u16_ffd1188[0][lane]
648 [info->
649 clock_speed_index];
650 if (reference_card == 5)
651 card_timing =
652 u16_ffd1188[1][lane]
653 [info->
654 clock_speed_index];
655 }
656
657 info->training.
658 lane_timings[0][channel][slot][rank]
659 [lane] =
660 u8_FFFD1218[info->
661 clock_speed_index];
662 info->training.
663 lane_timings[1][channel][slot][rank]
664 [lane] = 256;
665
666 for (tm_reg = 2; tm_reg < 4; tm_reg++)
667 info->training.
668 lane_timings[tm_reg]
669 [channel][slot][rank][lane]
670 =
671 u8_FFFD1240[channel]
672 [extended_silicon_revision]
673 [lane][2 * slot +
674 rank][info->
675 clock_speed_index]
676 + info->max4048[channel]
677 +
678 u8_FFFD0C78[channel]
679 [extended_silicon_revision]
680 [info->
681 mode4030[channel]][slot]
682 [rank][info->
683 clock_speed_index]
684 + card_timing;
685 for (tm_reg = 0; tm_reg < 4; tm_reg++)
686 write_500(info, channel,
687 info->training.
688 lane_timings[tm_reg]
689 [channel][slot][rank]
690 [lane],
691 get_timing_register_addr
692 (lane, tm_reg, slot,
693 rank), 9, 0);
694 }
695
696 card_timing_2 = 0;
697 if (!(extended_silicon_revision != 4
698 || (info->
699 populated_ranks_mask[channel] & 5) ==
700 5)) {
701 if ((info->
702 spd[channel][slot]
703 [REFERENCE_RAW_CARD_USED] & 0x1F)
704 == 3)
705 card_timing_2 =
706 u16_FFFE0EB8[0][info->
707 clock_speed_index];
708 if ((info->
709 spd[channel][slot]
710 [REFERENCE_RAW_CARD_USED] & 0x1F)
711 == 5)
712 card_timing_2 =
713 u16_FFFE0EB8[1][info->
714 clock_speed_index];
715 }
716
717 for (i = 0; i < 3; i++)
718 write_500(info, channel,
719 (card_timing_2 +
720 info->max4048[channel]
721 +
722 u8_FFFD0EF8[channel]
723 [extended_silicon_revision]
724 [info->
725 mode4030[channel]][info->
726 clock_speed_index]),
727 u16_fffd0c50[i][slot][rank],
728 8, 1);
729 write_500(info, channel,
730 (info->max4048[channel] +
731 u8_FFFD0C78[channel]
732 [extended_silicon_revision][info->
733 mode4030
734 [channel]]
735 [slot][rank][info->
736 clock_speed_index]),
737 u16_fffd0c70[slot][rank], 7, 1);
738 }
739 if (!info->populated_ranks_mask[channel])
740 continue;
741 for (i = 0; i < 3; i++)
742 write_500(info, channel,
743 (info->max4048[channel] +
744 info->avg4044[channel]
745 +
746 u8_FFFD17E0[channel]
747 [extended_silicon_revision][info->
748 mode4030
749 [channel]][info->
750 clock_speed_index]),
751 u16_fffd0c68[i], 8, 1);
752 }
753}
754
755static unsigned int fsbcycle_ps(struct raminfo *info)
756{
757 return 900000 / info->fsb_frequency;
758}
759
760/* The time of DDR transfer in ps. */
761static unsigned int halfcycle_ps(struct raminfo *info)
762{
763 return 3750 / (info->clock_speed_index + 3);
764}
765
766/* The time of clock cycle in ps. */
767static unsigned int cycle_ps(struct raminfo *info)
768{
769 return 2 * halfcycle_ps(info);
770}
771
772/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600773static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100774{
775 return (info->clock_speed_index + 3) * 120;
776}
777
778/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600779static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100780{
781 return 100 * frequency_11(info) / 9;
782}
783
Martin Roth468d02c2019-10-23 21:44:42 -0600784static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100785{
786 return (frequency_11(info) * 2) * ps / 900000;
787}
788
Martin Roth468d02c2019-10-23 21:44:42 -0600789static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100790{
791 return (frequency_11(info)) * ns / 900;
792}
793
794static void compute_derived_timings(struct raminfo *info)
795{
Martin Roth468d02c2019-10-23 21:44:42 -0600796 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100797 int extended_silicon_revision;
798 int some_delay_1_ps;
799 int some_delay_2_ps;
800 int some_delay_2_halfcycles_ceil;
801 int some_delay_2_halfcycles_floor;
802 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100803 int some_delay_3_ps_rounded;
804 int some_delay_1_cycle_ceil;
805 int some_delay_1_cycle_floor;
806
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100807 some_delay_3_ps_rounded = 0;
808 extended_silicon_revision = info->silicon_revision;
809 if (!info->silicon_revision)
810 for (channel = 0; channel < NUM_CHANNELS; channel++)
811 for (slot = 0; slot < NUM_SLOTS; slot++)
812 if ((info->
813 spd[channel][slot][MODULE_TYPE] & 0xF) ==
814 3)
815 extended_silicon_revision = 4;
816 if (info->board_lane_delay[7] < 5)
817 info->board_lane_delay[7] = 5;
818 info->revision_flag_1 = 2;
819 if (info->silicon_revision == 2 || info->silicon_revision == 3)
820 info->revision_flag_1 = 0;
821 if (info->revision < 16)
822 info->revision_flag_1 = 0;
823
824 if (info->revision < 8)
825 info->revision_flag_1 = 0;
826 if (info->revision >= 8 && (info->silicon_revision == 0
827 || info->silicon_revision == 1))
828 some_delay_2_ps = 735;
829 else
830 some_delay_2_ps = 750;
831
832 if (info->revision >= 0x10 && (info->silicon_revision == 0
833 || info->silicon_revision == 1))
834 some_delay_1_ps = 3929;
835 else
836 some_delay_1_ps = 3490;
837
838 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
839 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
840 if (some_delay_1_ps % cycle_ps(info))
841 some_delay_1_cycle_ceil++;
842 else
843 some_delay_1_cycle_floor--;
844 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
845 if (info->revision_flag_1)
846 some_delay_2_ps = halfcycle_ps(info) >> 6;
847 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100848 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100849 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
850 375;
851 some_delay_3_ps =
852 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
853 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200854 if (some_delay_3_ps >= 150) {
855 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100856 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200857 some_delay_3_ps_rounded =
858 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
859 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100860 }
861 some_delay_2_halfcycles_ceil =
862 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
863 2 * (some_delay_1_cycle_ceil - 1);
864 if (info->revision_flag_1 && some_delay_3_ps < 150)
865 some_delay_2_halfcycles_ceil++;
866 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
867 if (info->revision < 0x10)
868 some_delay_2_halfcycles_floor =
869 some_delay_2_halfcycles_ceil - 1;
870 if (!info->revision_flag_1)
871 some_delay_2_halfcycles_floor++;
872 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
873 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
874 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
875 || (info->populated_ranks[1][0][0]
876 && info->populated_ranks[1][1][0]))
877 info->max_slots_used_in_channel = 2;
878 else
879 info->max_slots_used_in_channel = 1;
880 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200881 MCHBAR32(0x244 + (channel << 10)) =
882 ((info->revision < 8) ? 1 : 0x200) |
883 ((2 - info->max_slots_used_in_channel) << 17) |
884 (channel << 21) |
885 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100886 if (info->max_slots_used_in_channel == 1) {
887 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
888 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
889 } else {
890 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 */
891 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
892 || (count_ranks_in_channel(info, 1) ==
893 2)) ? 2 : 3;
894 }
895 for (channel = 0; channel < NUM_CHANNELS; channel++) {
896 int max_of_unk;
897 int min_of_unk_2;
898
899 int i, count;
900 int sum;
901
902 if (!info->populated_ranks_mask[channel])
903 continue;
904
905 max_of_unk = 0;
906 min_of_unk_2 = 32767;
907
908 sum = 0;
909 count = 0;
910 for (i = 0; i < 3; i++) {
911 int unk1;
912 if (info->revision < 8)
913 unk1 =
914 u8_FFFD1891[0][channel][info->
915 clock_speed_index]
916 [i];
917 else if (!
918 (info->revision >= 0x10
919 || info->revision_flag_1))
920 unk1 =
921 u8_FFFD1891[1][channel][info->
922 clock_speed_index]
923 [i];
924 else
925 unk1 = 0;
926 for (slot = 0; slot < NUM_SLOTS; slot++)
927 for (rank = 0; rank < NUM_RANKS; rank++) {
928 int a = 0;
929 int b = 0;
930
931 if (!info->
932 populated_ranks[channel][slot]
933 [rank])
934 continue;
935 if (extended_silicon_revision == 4
936 && (info->
937 populated_ranks_mask[channel] &
938 5) != 5) {
939 if ((info->
940 spd[channel][slot]
941 [REFERENCE_RAW_CARD_USED] &
942 0x1F) == 3) {
943 a = u16_ffd1178[0]
944 [info->
945 clock_speed_index];
946 b = u16_fe0eb8[0][info->
947 clock_speed_index];
948 } else
949 if ((info->
950 spd[channel][slot]
951 [REFERENCE_RAW_CARD_USED]
952 & 0x1F) == 5) {
953 a = u16_ffd1178[1]
954 [info->
955 clock_speed_index];
956 b = u16_fe0eb8[1][info->
957 clock_speed_index];
958 }
959 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100960 min_of_unk_2 = MIN(min_of_unk_2, a);
961 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100962 if (rank == 0) {
963 sum += a;
964 count++;
965 }
966 {
967 int t;
968 t = b +
969 u8_FFFD0EF8[channel]
970 [extended_silicon_revision]
971 [info->
972 mode4030[channel]][info->
973 clock_speed_index];
974 if (unk1 >= t)
975 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100976 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100977 unk1 - t);
978 }
979 }
980 {
981 int t =
982 u8_FFFD17E0[channel]
983 [extended_silicon_revision][info->
984 mode4030
985 [channel]]
986 [info->clock_speed_index] + min_of_unk_2;
987 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100988 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100989 }
990 }
991
Jacob Garber64fb4a32019-06-10 17:29:18 -0600992 if (count == 0)
993 die("No memory ranks found for channel %u\n", channel);
994
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100995 info->avg4044[channel] = sum / count;
996 info->max4048[channel] = max_of_unk;
997 }
998}
999
1000static void jedec_read(struct raminfo *info,
1001 int channel, int slot, int rank,
1002 int total_rank, u8 addr3, unsigned int value)
1003{
1004 /* Handle mirrored mapping. */
1005 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001006 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1007 ((addr3 >> 1) & 0x10);
1008 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1009 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001010
1011 /* Handle mirrored mapping. */
1012 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1013 value =
1014 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1015 << 1);
1016
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001017 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001018
Felix Held04be2dd2018-07-29 04:53:22 +02001019 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1020 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001021
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001022 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001023}
1024
1025enum {
1026 MR1_RZQ12 = 512,
1027 MR1_RZQ2 = 64,
1028 MR1_RZQ4 = 4,
1029 MR1_ODS34OHM = 2
1030};
1031
1032enum {
1033 MR0_BT_INTERLEAVED = 8,
1034 MR0_DLL_RESET_ON = 256
1035};
1036
1037enum {
1038 MR2_RTT_WR_DISABLED = 0,
1039 MR2_RZQ2 = 1 << 10
1040};
1041
1042static void jedec_init(struct raminfo *info)
1043{
1044 int write_recovery;
1045 int channel, slot, rank;
1046 int total_rank;
1047 int dll_on;
1048 int self_refresh_temperature;
1049 int auto_self_refresh;
1050
1051 auto_self_refresh = 1;
1052 self_refresh_temperature = 1;
1053 if (info->board_lane_delay[3] <= 10) {
1054 if (info->board_lane_delay[3] <= 8)
1055 write_recovery = info->board_lane_delay[3] - 4;
1056 else
1057 write_recovery = 5;
1058 } else {
1059 write_recovery = 6;
1060 }
1061 FOR_POPULATED_RANKS {
1062 auto_self_refresh &=
1063 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1064 self_refresh_temperature &=
1065 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1066 }
1067 if (auto_self_refresh == 1)
1068 self_refresh_temperature = 0;
1069
1070 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1071 || (info->populated_ranks[0][0][0]
1072 && info->populated_ranks[0][1][0])
1073 || (info->populated_ranks[1][0][0]
1074 && info->populated_ranks[1][1][0]));
1075
1076 total_rank = 0;
1077
1078 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1079 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1080 int rzq_reg58e;
1081
1082 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1083 rzq_reg58e = 64;
1084 rtt = MR1_RZQ2;
1085 if (info->clock_speed_index != 0) {
1086 rzq_reg58e = 4;
1087 if (info->populated_ranks_mask[channel] == 3)
1088 rtt = MR1_RZQ4;
1089 }
1090 } else {
1091 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1092 rtt = MR1_RZQ12;
1093 rzq_reg58e = 64;
1094 rtt_wr = MR2_RZQ2;
1095 } else {
1096 rzq_reg58e = 4;
1097 rtt = MR1_RZQ4;
1098 }
1099 }
1100
Felix Held04be2dd2018-07-29 04:53:22 +02001101 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1102 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1103 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1104 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1105 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001106
1107 for (slot = 0; slot < NUM_SLOTS; slot++)
1108 for (rank = 0; rank < NUM_RANKS; rank++)
1109 if (info->populated_ranks[channel][slot][rank]) {
1110 jedec_read(info, channel, slot, rank,
1111 total_rank, 0x28,
1112 rtt_wr | (info->
1113 clock_speed_index
1114 << 3)
1115 | (auto_self_refresh << 6) |
1116 (self_refresh_temperature <<
1117 7));
1118 jedec_read(info, channel, slot, rank,
1119 total_rank, 0x38, 0);
1120 jedec_read(info, channel, slot, rank,
1121 total_rank, 0x18,
1122 rtt | MR1_ODS34OHM);
1123 jedec_read(info, channel, slot, rank,
1124 total_rank, 6,
1125 (dll_on << 12) |
1126 (write_recovery << 9)
1127 | ((info->cas_latency - 4) <<
1128 4) | MR0_BT_INTERLEAVED |
1129 MR0_DLL_RESET_ON);
1130 total_rank++;
1131 }
1132 }
1133}
1134
1135static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1136{
Martin Roth468d02c2019-10-23 21:44:42 -06001137 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001138 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1139 unsigned int channel_0_non_interleaved;
1140
1141 FOR_ALL_RANKS {
1142 if (info->populated_ranks[channel][slot][rank]) {
1143 total_mb[channel] +=
1144 pre_jedec ? 256 : (256 << info->
1145 density[channel][slot] >> info->
1146 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001147 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1148 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1149 (info->is_x16_module[channel][slot] |
1150 ((info->density[channel][slot] + 1) << 1))) |
1151 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001152 }
Felix Held04be2dd2018-07-29 04:53:22 +02001153 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1154 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001155 }
1156
1157 info->total_memory_mb = total_mb[0] + total_mb[1];
1158
1159 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001160 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 info->non_interleaved_part_mb =
1162 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1163 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001164 MCHBAR32(0x100) = channel_0_non_interleaved |
1165 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001166 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001167 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001168}
1169
1170static void program_board_delay(struct raminfo *info)
1171{
1172 int cas_latency_shift;
1173 int some_delay_ns;
1174 int some_delay_3_half_cycles;
1175
Martin Roth468d02c2019-10-23 21:44:42 -06001176 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001177 int high_multiplier;
1178 int lane_3_delay;
1179 int cas_latency_derived;
1180
1181 high_multiplier = 0;
1182 some_delay_ns = 200;
1183 some_delay_3_half_cycles = 4;
1184 cas_latency_shift = info->silicon_revision == 0
1185 || info->silicon_revision == 1 ? 1 : 0;
1186 if (info->revision < 8) {
1187 some_delay_ns = 600;
1188 cas_latency_shift = 0;
1189 }
1190 {
1191 int speed_bit;
1192 speed_bit =
1193 ((info->clock_speed_index > 1
1194 || (info->silicon_revision != 2
1195 && info->silicon_revision != 3))) ^ (info->revision >=
1196 0x10);
1197 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1198 3, 1);
1199 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1200 3, 1);
1201 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1202 && (info->silicon_revision == 2
1203 || info->silicon_revision == 3))
1204 rmw_1d0(0x116, 5, 2, 4, 1);
1205 }
Felix Held04be2dd2018-07-29 04:53:22 +02001206 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1207 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001208
Felix Held04be2dd2018-07-29 04:53:22 +02001209 MCHBAR8(0x124) = info->board_lane_delay[4] +
1210 ((frequency_01(info) + 999) / 1000);
1211 MCHBAR16(0x125) = 0x1360;
1212 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001213 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001214 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001215 high_multiplier = 1;
1216 some_delay_2_half_cycles = ps_to_halfcycles(info,
1217 ((3 *
1218 fsbcycle_ps(info))
1219 >> 1) +
1220 (halfcycle_ps(info)
1221 *
1222 reg178_min[info->
1223 clock_speed_index]
1224 >> 6)
1225 +
1226 4 *
1227 halfcycle_ps(info)
1228 + 2230);
1229 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001230 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001231 (frequency_11(info) * 2) * (28 -
1232 some_delay_2_half_cycles) /
1233 (frequency_11(info) * 2 -
1234 4 * (info->fsb_frequency))) >> 3, 7);
1235 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001236 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001237 some_delay_3_half_cycles = 3;
1238 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001239 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1240 MCHBAR32(0x224 + (channel << 10)) =
1241 (info->max_slots_used_in_channel - 1) |
1242 ((info->cas_latency - 5 - info->clock_speed_index)
1243 << 21) | ((info->max_slots_used_in_channel +
1244 info->cas_latency - cas_latency_shift - 4) << 16) |
1245 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1246 ((info->cas_latency - info->clock_speed_index +
1247 info->max_slots_used_in_channel - 6) << 8);
1248 MCHBAR32(0x228 + (channel << 10)) =
1249 info->max_slots_used_in_channel;
1250 MCHBAR8(0x239 + (channel << 10)) = 32;
1251 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1252 (some_delay_3_half_cycles << 25) | 0x840000;
1253 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1254 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1255 MCHBAR32(0x24c + (channel << 10)) =
1256 ((!!info->clock_speed_index) << 17) |
1257 (((2 + info->clock_speed_index -
1258 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001259
Felix Held04be2dd2018-07-29 04:53:22 +02001260 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1261 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1262 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001263
1264 write_500(info, channel,
1265 ((!info->populated_ranks[channel][1][1])
1266 | (!info->populated_ranks[channel][1][0] << 1)
1267 | (!info->populated_ranks[channel][0][1] << 2)
1268 | (!info->populated_ranks[channel][0][0] << 3)),
1269 0x4c9, 4, 1);
1270 }
1271
Felix Held22ca8cb2018-07-29 05:09:44 +02001272 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001273 {
1274 u8 freq_divisor = 2;
1275 if (info->fsb_frequency == frequency_11(info))
1276 freq_divisor = 3;
1277 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1278 freq_divisor = 1;
1279 else
1280 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001281 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001282 }
1283
1284 if (info->board_lane_delay[3] <= 10) {
1285 if (info->board_lane_delay[3] <= 8)
1286 lane_3_delay = info->board_lane_delay[3];
1287 else
1288 lane_3_delay = 10;
1289 } else {
1290 lane_3_delay = 12;
1291 }
1292 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1293 if (info->clock_speed_index > 1)
1294 cas_latency_derived++;
1295 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001296 MCHBAR32(0x240 + (channel << 10)) =
1297 ((info->clock_speed_index == 0) * 0x11000) |
1298 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1299 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001300 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1301 0x609, 6, 1);
1302 write_500(info, channel,
1303 info->clock_speed_index + 2 * info->cas_latency - 7,
1304 0x601, 6, 1);
1305
Felix Held04be2dd2018-07-29 04:53:22 +02001306 MCHBAR32(0x250 + (channel << 10)) =
1307 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1308 (info->board_lane_delay[7] << 2) |
1309 (info->board_lane_delay[4] << 16) |
1310 (info->board_lane_delay[1] << 25) |
1311 (info->board_lane_delay[1] << 29) | 1;
1312 MCHBAR32(0x254 + (channel << 10)) =
1313 (info->board_lane_delay[1] >> 3) |
1314 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1315 0x80 | (info->board_lane_delay[6] << 1) |
1316 (info->board_lane_delay[2] << 28) |
1317 (cas_latency_derived << 16) | 0x4700000;
1318 MCHBAR32(0x258 + (channel << 10)) =
1319 ((info->board_lane_delay[5] + info->clock_speed_index +
1320 9) << 12) | ((info->clock_speed_index -
1321 info->cas_latency + 12) << 8) |
1322 (info->board_lane_delay[2] << 17) |
1323 (info->board_lane_delay[4] << 24) | 0x47;
1324 MCHBAR32(0x25c + (channel << 10)) =
1325 (info->board_lane_delay[1] << 1) |
1326 (info->board_lane_delay[0] << 8) | 0x1da50000;
1327 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1328 MCHBAR8(0x5f8 + (channel << 10)) =
1329 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001330 }
1331
1332 program_modules_memory_map(info, 1);
1333
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001334 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001335 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1336 MCHBAR16_OR(0x612, 0x100);
1337 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001338 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001339 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001340 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001341 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001342 }
1343}
1344
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001345#define DEFAULT_PCI_MMIO_SIZE 2048
1346#define HOST_BRIDGE PCI_DEVFN(0, 0)
1347
1348static unsigned int get_mmio_size(void)
1349{
1350 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001351 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001352
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001353 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001354 if (dev)
1355 cfg = dev->chip_info;
1356
1357 /* If this is zero, it just means devicetree.cb didn't set it */
1358 if (!cfg || cfg->pci_mmio_size == 0)
1359 return DEFAULT_PCI_MMIO_SIZE;
1360 else
1361 return cfg->pci_mmio_size;
1362}
1363
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001364static void program_total_memory_map(struct raminfo *info)
1365{
Angel Pons9333b742020-07-22 16:04:15 +02001366 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001367 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001368 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001369 unsigned int uma_base_igd;
1370 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001371 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001372 int memory_remap;
1373 unsigned int memory_map[8];
1374 int i;
1375 unsigned int current_limit;
1376 unsigned int tseg_base;
1377 int uma_size_igd = 0, uma_size_gtt = 0;
1378
1379 memset(memory_map, 0, sizeof(memory_map));
1380
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001381 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001382 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001383 gav(t);
1384 const int uma_sizes_gtt[16] =
1385 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1386 /* Igd memory */
1387 const int uma_sizes_igd[16] = {
1388 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1389 256, 512
1390 };
1391
1392 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1393 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1394 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001396 mmio_size = get_mmio_size();
1397
Angel Pons9333b742020-07-22 16:04:15 +02001398 tom = info->total_memory_mb;
1399 if (tom == 4096)
1400 tom = 4032;
1401 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1402 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1403 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001404 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001405 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001407 remap_base = MAX(4096, touud);
1408 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001409 }
Angel Pons9333b742020-07-22 16:04:15 +02001410 if (touud > 4096)
1411 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 quickpath_reserved = 0;
1413
Angel Pons3ab19b32020-07-22 16:29:54 +02001414 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415
Jacob Garber975a7e32019-06-10 16:32:47 -06001416 gav(t);
1417
1418 if (t & 0x800) {
1419 u32 shift = t >> 20;
1420 if (shift == 0)
1421 die("Quickpath value is 0\n");
1422 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001424
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001425 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001426 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001427
Angel Pons9333b742020-07-22 16:04:15 +02001428 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 uma_base_gtt = uma_base_igd - uma_size_gtt;
1430 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1431 if (!memory_remap)
1432 tseg_base -= quickpath_reserved;
1433 tseg_base = ALIGN_DOWN(tseg_base, 8);
1434
Angel Pons16fe1e02020-07-22 16:12:33 +02001435 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1436 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001438 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1439 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001441 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442
1443 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001444 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1445 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001447 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448
1449 current_limit = 0;
1450 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1451 memory_map[1] = 4096;
1452 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001453 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001454 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1456 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001457 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458 }
1459}
1460
1461static void collect_system_info(struct raminfo *info)
1462{
1463 u32 capid0[3];
1464 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001465 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466
1467 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001468 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1469 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 if (!info->memory_reserved_for_heci_mb) {
1472 /* Wait for ME to be ready */
1473 intel_early_me_init();
1474 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1475 }
1476
1477 for (i = 0; i < 3; i++)
1478 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001479 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001480 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1482
1483 if ((capid0[1] >> 11) & 1)
1484 info->uma_enabled = 0;
1485 else
1486 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001487 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1489 info->silicon_revision = 0;
1490
1491 if (capid0[2] & 2) {
1492 info->silicon_revision = 0;
1493 info->max_supported_clock_speed_index = 2;
1494 for (channel = 0; channel < NUM_CHANNELS; channel++)
1495 if (info->populated_ranks[channel][0][0]
1496 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1497 3) {
1498 info->silicon_revision = 2;
1499 info->max_supported_clock_speed_index = 1;
1500 }
1501 } else {
1502 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1503 case 1:
1504 case 2:
1505 info->silicon_revision = 3;
1506 break;
1507 case 3:
1508 info->silicon_revision = 0;
1509 break;
1510 case 0:
1511 info->silicon_revision = 2;
1512 break;
1513 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001514 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001515 case 0x40:
1516 info->silicon_revision = 0;
1517 break;
1518 case 0x48:
1519 info->silicon_revision = 1;
1520 break;
1521 }
1522 }
1523}
1524
1525static void write_training_data(struct raminfo *info)
1526{
1527 int tm, channel, slot, rank, lane;
1528 if (info->revision < 8)
1529 return;
1530
1531 for (tm = 0; tm < 4; tm++)
1532 for (channel = 0; channel < NUM_CHANNELS; channel++)
1533 for (slot = 0; slot < NUM_SLOTS; slot++)
1534 for (rank = 0; rank < NUM_RANKS; rank++)
1535 for (lane = 0; lane < 9; lane++)
1536 write_500(info, channel,
1537 info->
1538 cached_training->
1539 lane_timings[tm]
1540 [channel][slot][rank]
1541 [lane],
1542 get_timing_register_addr
1543 (lane, tm, slot,
1544 rank), 9, 0);
1545 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1546 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1547}
1548
1549static void dump_timings(struct raminfo *info)
1550{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001551 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001552 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001553 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001554 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001555 slot, rank);
1556 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001557 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001558 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001559 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001560 read_500(info, channel,
1561 get_timing_register_addr
1562 (lane, i, slot, rank),
1563 9),
1564 info->training.
1565 lane_timings[i][channel][slot][rank]
1566 [lane]);
1567 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001568 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 }
1570 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575}
1576
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001577/* Read timings and other registers that need to be restored verbatim and
1578 put them to CBMEM.
1579 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580static void save_timings(struct raminfo *info)
1581{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 int channel, slot, rank, lane, i;
1584
1585 train = info->training;
1586 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1587 for (i = 0; i < 4; i++)
1588 train.lane_timings[i][channel][slot][rank][lane] =
1589 read_500(info, channel,
1590 get_timing_register_addr(lane, i, slot,
1591 rank), 9);
1592 train.reg_178 = read_1d0(0x178, 7);
1593 train.reg_10b = read_1d0(0x10b, 6);
1594
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1596 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001597 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001598 train.reg274265[channel][0] = reg32 >> 16;
1599 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001600 train.reg274265[channel][2] =
1601 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001602 }
Felix Held04be2dd2018-07-29 04:53:22 +02001603 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1604 train.reg_6dc = MCHBAR32(0x6dc);
1605 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001606
Arthur Heymansb3282092019-04-14 17:53:28 +02001607 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1608 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001609
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001611 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1612 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001613}
1614
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615static const struct ram_training *get_cached_training(void)
1616{
Shelley Chenad9cd682020-07-23 16:10:52 -07001617 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1618 MRC_CACHE_VERSION,
1619 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621
1622/* FIXME: add timeout. */
1623static void wait_heci_ready(void)
1624{
Felix Held04be2dd2018-07-29 04:53:22 +02001625 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1626 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001627 write32((DEFAULT_HECIBAR + 0x4),
1628 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629}
1630
1631/* FIXME: add timeout. */
1632static void wait_heci_cb_avail(int len)
1633{
1634 union {
1635 struct mei_csr csr;
1636 u32 raw;
1637 } csr;
1638
Felix Held22ca8cb2018-07-29 05:09:44 +02001639 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1640 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641
1642 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001643 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001644 while (len >
1645 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001646 csr.csr.buffer_read_ptr))
1647 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648}
1649
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001650static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651{
1652 int len = (head->length + 3) / 4;
1653 int i;
1654
1655 wait_heci_cb_avail(len + 1);
1656
1657 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001658 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001660 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001661
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001662 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1663 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664}
1665
1666static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001667send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668{
1669 struct mei_header head;
1670 int maxlen;
1671
1672 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001673 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001674
1675 while (len) {
1676 int cur = len;
1677 if (cur > maxlen) {
1678 cur = maxlen;
1679 head.is_complete = 0;
1680 } else
1681 head.is_complete = 1;
1682 head.length = cur;
1683 head.reserved = 0;
1684 head.client_address = clientaddress;
1685 head.host_address = hostaddress;
1686 send_heci_packet(&head, (u32 *) msg);
1687 len -= cur;
1688 msg += cur;
1689 }
1690}
1691
1692/* FIXME: Add timeout. */
1693static int
Angel Pons86907462020-09-14 18:48:59 +02001694recv_heci_packet(struct mei_header *head, u32 *packet,
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001695 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696{
1697 union {
1698 struct mei_csr csr;
1699 u32 raw;
1700 } csr;
1701 int i = 0;
1702
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001703 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001705 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001706 }
Felix Held04be2dd2018-07-29 04:53:22 +02001707 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1708 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001709 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001711 write32(DEFAULT_HECIBAR + 0x4,
1712 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001713 *packet_size = 0;
1714 return 0;
1715 }
1716 if (head->length + 4 > 4 * csr.csr.buffer_depth
1717 || head->length > *packet_size) {
1718 *packet_size = 0;
1719 return -1;
1720 }
1721
1722 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001724 while (((head->length + 3) >> 2) >
1725 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1726 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727
1728 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 *packet_size = head->length;
1731 if (!csr.csr.ready)
1732 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001733 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 return 0;
1735}
1736
1737/* FIXME: Add timeout. */
1738static int
Angel Pons86907462020-09-14 18:48:59 +02001739recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740{
1741 struct mei_header head;
1742 int current_position;
1743
1744 current_position = 0;
1745 while (1) {
1746 u32 current_size;
1747 current_size = *message_size - current_position;
1748 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001749 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750 &current_size) == -1)
1751 break;
1752 if (!current_size)
1753 break;
1754 current_position += current_size;
1755 if (head.is_complete) {
1756 *message_size = current_position;
1757 return 0;
1758 }
1759
1760 if (current_position >= *message_size)
1761 break;
1762 }
1763 *message_size = 0;
1764 return -1;
1765}
1766
1767static void send_heci_uma_message(struct raminfo *info)
1768{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001769 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001770 u8 group_id;
1771 u8 command;
1772 u8 reserved;
1773 u8 result;
1774 u8 field2;
1775 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001776 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001777
1778 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1779 reply.command = 0;
1780
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001781 struct uma_message {
1782 u8 group_id;
1783 u8 cmd;
1784 u8 reserved;
1785 u8 result;
1786 u32 c2;
1787 u64 heci_uma_addr;
1788 u32 memory_reserved_for_heci_mb;
1789 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001790 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001791 0, MKHI_SET_UMA, 0, 0,
1792 0x82,
1793 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1794 u32 reply_size;
1795
1796 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1797
1798 reply_size = sizeof(reply);
Angel Pons86907462020-09-14 18:48:59 +02001799 if (recv_heci_message((u32 *) & reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001800 return;
1801
1802 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1803 die("HECI init failed\n");
1804}
1805
1806static void setup_heci_uma(struct raminfo *info)
1807{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001808 info->heci_uma_addr = 0;
Angel Pons298d34d2020-09-14 18:58:53 +02001809 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001810 return;
1811
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001812 info->heci_uma_addr =
1813 ((u64)
Angel Pons16fe1e02020-07-22 16:12:33 +02001814 ((((u64) pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001815 info->memory_reserved_for_heci_mb)) << 20;
1816
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001817 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001818 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001819 write32(DEFAULT_DMIBAR + 0x14,
1820 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1821 write32(DEFAULT_RCBA + 0x14,
1822 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1823 write32(DEFAULT_DMIBAR + 0x20,
1824 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1825 write32(DEFAULT_RCBA + 0x20,
1826 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1827 write32(DEFAULT_DMIBAR + 0x2c,
1828 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1829 write32(DEFAULT_RCBA + 0x30,
1830 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1831 write32(DEFAULT_DMIBAR + 0x38,
1832 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1833 write32(DEFAULT_RCBA + 0x40,
1834 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001836 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1837 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001838 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1839 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1840 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841 }
1842
Felix Held04be2dd2018-07-29 04:53:22 +02001843 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844
1845 send_heci_uma_message(info);
1846
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001847 pci_write_config32(HECIDEV, 0x10, 0x0);
1848 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849
1850}
1851
1852static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1853{
1854 int ranks_in_channel;
1855 ranks_in_channel = info->populated_ranks[channel][0][0]
1856 + info->populated_ranks[channel][0][1]
1857 + info->populated_ranks[channel][1][0]
1858 + info->populated_ranks[channel][1][1];
1859
1860 /* empty channel */
1861 if (ranks_in_channel == 0)
1862 return 1;
1863
1864 if (ranks_in_channel != ranks)
1865 return 0;
1866 /* single slot */
1867 if (info->populated_ranks[channel][0][0] !=
1868 info->populated_ranks[channel][1][0])
1869 return 1;
1870 if (info->populated_ranks[channel][0][1] !=
1871 info->populated_ranks[channel][1][1])
1872 return 1;
1873 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1874 return 0;
1875 if (info->density[channel][0] != info->density[channel][1])
1876 return 0;
1877 return 1;
1878}
1879
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001880static void read_4090(struct raminfo *info)
1881{
1882 int i, channel, slot, rank, lane;
1883 for (i = 0; i < 2; i++)
1884 for (slot = 0; slot < NUM_SLOTS; slot++)
1885 for (rank = 0; rank < NUM_RANKS; rank++)
1886 for (lane = 0; lane < 9; lane++)
1887 info->training.
1888 lane_timings[0][i][slot][rank][lane]
1889 = 32;
1890
1891 for (i = 1; i < 4; i++)
1892 for (channel = 0; channel < NUM_CHANNELS; channel++)
1893 for (slot = 0; slot < NUM_SLOTS; slot++)
1894 for (rank = 0; rank < NUM_RANKS; rank++)
1895 for (lane = 0; lane < 9; lane++) {
1896 info->training.
1897 lane_timings[i][channel]
1898 [slot][rank][lane] =
1899 read_500(info, channel,
1900 get_timing_register_addr
1901 (lane, i, slot,
1902 rank), 9)
1903 + (i == 1) * 11; // !!!!
1904 }
1905
1906}
1907
1908static u32 get_etalon2(int flip, u32 addr)
1909{
1910 const u16 invmask[] = {
1911 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1912 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1913 };
1914 u32 ret;
1915 u32 comp4 = addr / 480;
1916 addr %= 480;
1917 u32 comp1 = addr & 0xf;
1918 u32 comp2 = (addr >> 4) & 1;
1919 u32 comp3 = addr >> 5;
1920
1921 if (comp4)
1922 ret = 0x1010101 << (comp4 - 1);
1923 else
1924 ret = 0;
1925 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1926 ret = ~ret;
1927
1928 return ret;
1929}
1930
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001931static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001932{
1933 msr_t msr = {.lo = 0, .hi = 0 };
1934
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001935 wrmsr(MTRR_PHYS_BASE(3), msr);
1936 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001937}
1938
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001939static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001940{
1941 msr_t msr;
1942 msr.lo = base | MTRR_TYPE_WRPROT;
1943 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001944 wrmsr(MTRR_PHYS_BASE(3), msr);
1945 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001946 & 0xffffffff);
1947 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001948 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001949}
1950
1951static void flush_cache(u32 start, u32 size)
1952{
1953 u32 end;
1954 u32 addr;
1955
1956 end = start + (ALIGN_DOWN(size + 4096, 4096));
1957 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001958 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001959}
1960
1961static void clear_errors(void)
1962{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001963 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001964}
1965
1966static void write_testing(struct raminfo *info, int totalrank, int flip)
1967{
1968 int nwrites = 0;
1969 /* in 8-byte units. */
1970 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001971 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001973 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001974 for (offset = 0; offset < 9 * 480; offset += 2) {
1975 write32(base + offset * 8, get_etalon2(flip, offset));
1976 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1977 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1978 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1979 nwrites += 4;
1980 if (nwrites >= 320) {
1981 clear_errors();
1982 nwrites = 0;
1983 }
1984 }
1985}
1986
1987static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1988{
1989 u8 failmask = 0;
1990 int i;
1991 int comp1, comp2, comp3;
1992 u32 failxor[2] = { 0, 0 };
1993
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001994 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995
1996 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1997 for (comp1 = 0; comp1 < 4; comp1++)
1998 for (comp2 = 0; comp2 < 60; comp2++) {
1999 u32 re[4];
2000 u32 curroffset =
2001 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2002 read128((total_rank << 28) | (curroffset << 3),
2003 (u64 *) re);
2004 failxor[0] |=
2005 get_etalon2(flip, curroffset) ^ re[0];
2006 failxor[1] |=
2007 get_etalon2(flip, curroffset) ^ re[1];
2008 failxor[0] |=
2009 get_etalon2(flip, curroffset | 1) ^ re[2];
2010 failxor[1] |=
2011 get_etalon2(flip, curroffset | 1) ^ re[3];
2012 }
2013 for (i = 0; i < 8; i++)
2014 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2015 failmask |= 1 << i;
2016 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002017 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002018 flush_cache((total_rank << 28), 1728 * 5 * 4);
2019 return failmask;
2020}
2021
2022const u32 seed1[0x18] = {
2023 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2024 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2025 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2026 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2027 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2028 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2029};
2030
2031static u32 get_seed2(int a, int b)
2032{
2033 const u32 seed2[5] = {
2034 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2035 0x5b6db6db,
2036 };
2037 u32 r;
2038 r = seed2[(a + (a >= 10)) / 5];
2039 return b ? ~r : r;
2040}
2041
2042static int make_shift(int comp2, int comp5, int x)
2043{
2044 const u8 seed3[32] = {
2045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2046 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2047 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2048 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2049 };
2050
2051 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2052}
2053
2054static u32 get_etalon(int flip, u32 addr)
2055{
2056 u32 mask_byte = 0;
2057 int comp1 = (addr >> 1) & 1;
2058 int comp2 = (addr >> 3) & 0x1f;
2059 int comp3 = (addr >> 8) & 0xf;
2060 int comp4 = (addr >> 12) & 0xf;
2061 int comp5 = (addr >> 16) & 0x1f;
2062 u32 mask_bit = ~(0x10001 << comp3);
2063 u32 part1;
2064 u32 part2;
2065 int byte;
2066
2067 part2 =
2068 ((seed1[comp5] >>
2069 make_shift(comp2, comp5,
2070 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2071 part1 =
2072 ((seed1[comp5] >>
2073 make_shift(comp2, comp5,
2074 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2075
2076 for (byte = 0; byte < 4; byte++)
2077 if ((get_seed2(comp5, comp4) >>
2078 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2079 mask_byte |= 0xff << (8 * byte);
2080
2081 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2082 (comp3 + 16));
2083}
2084
2085static void
2086write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2087 char flip)
2088{
2089 int i;
2090 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002091 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2092 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002093}
2094
2095static u8
2096check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2097 char flip)
2098{
2099 u8 failmask = 0;
2100 u32 failxor[2];
2101 int i;
2102 int comp1, comp2, comp3;
2103
2104 failxor[0] = 0;
2105 failxor[1] = 0;
2106
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002107 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002108 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2109 for (comp1 = 0; comp1 < 16; comp1++)
2110 for (comp2 = 0; comp2 < 64; comp2++) {
2111 u32 addr =
2112 (totalrank << 28) | (region << 25) | (block
2113 << 16)
2114 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2115 2);
2116 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002117 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002118 }
2119 for (i = 0; i < 8; i++)
2120 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2121 failmask |= 1 << i;
2122 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002123 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002124 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2125 return failmask;
2126}
2127
2128static int check_bounded(unsigned short *vals, u16 bound)
2129{
2130 int i;
2131
2132 for (i = 0; i < 8; i++)
2133 if (vals[i] < bound)
2134 return 0;
2135 return 1;
2136}
2137
2138enum state {
2139 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2140};
2141
2142static int validate_state(enum state *in)
2143{
2144 int i;
2145 for (i = 0; i < 8; i++)
2146 if (in[i] != COMPLETE)
2147 return 0;
2148 return 1;
2149}
2150
2151static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002152do_fsm(enum state *state, u16 *counter,
2153 u8 fail_mask, int margin, int uplimit,
2154 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002155{
2156 int lane;
2157
2158 for (lane = 0; lane < 8; lane++) {
2159 int is_fail = (fail_mask >> lane) & 1;
2160 switch (state[lane]) {
2161 case BEFORE_USABLE:
2162 if (!is_fail) {
2163 counter[lane] = 1;
2164 state[lane] = AT_USABLE;
2165 break;
2166 }
2167 counter[lane] = 0;
2168 state[lane] = BEFORE_USABLE;
2169 break;
2170 case AT_USABLE:
2171 if (!is_fail) {
2172 ++counter[lane];
2173 if (counter[lane] >= margin) {
2174 state[lane] = AT_MARGIN;
2175 res_low[lane] = val - margin + 1;
2176 break;
2177 }
2178 state[lane] = 1;
2179 break;
2180 }
2181 counter[lane] = 0;
2182 state[lane] = BEFORE_USABLE;
2183 break;
2184 case AT_MARGIN:
2185 if (is_fail) {
2186 state[lane] = COMPLETE;
2187 res_high[lane] = val - 1;
2188 } else {
2189 counter[lane]++;
2190 state[lane] = AT_MARGIN;
2191 if (val == uplimit) {
2192 state[lane] = COMPLETE;
2193 res_high[lane] = uplimit;
2194 }
2195 }
2196 break;
2197 case COMPLETE:
2198 break;
2199 }
2200 }
2201}
2202
2203static void
2204train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2205 u8 total_rank, u8 reg_178, int first_run, int niter,
2206 timing_bounds_t * timings)
2207{
2208 int lane;
2209 enum state state[8];
2210 u16 count[8];
2211 u8 lower_usable[8];
2212 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002213 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002214 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002215 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002216
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002217 for (i = 0; i < 8; i++)
2218 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002219
2220 if (!first_run) {
2221 int is_all_ok = 1;
2222 for (lane = 0; lane < 8; lane++)
2223 if (timings[reg_178][channel][slot][rank][lane].
2224 smallest ==
2225 timings[reg_178][channel][slot][rank][lane].
2226 largest) {
2227 timings[reg_178][channel][slot][rank][lane].
2228 smallest = 0;
2229 timings[reg_178][channel][slot][rank][lane].
2230 largest = 0;
2231 is_all_ok = 0;
2232 }
2233 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002234 for (i = 0; i < 8; i++)
2235 state[i] = COMPLETE;
2236 }
2237 }
2238
2239 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2240 u8 failmask = 0;
2241 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2242 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2243 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002244 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002245 do_fsm(state, count, failmask, 5, 47, lower_usable,
2246 upper_usable, reg1b3);
2247 }
2248
2249 if (reg1b3) {
2250 write_1d0(0, 0x1b3, 6, 1);
2251 write_1d0(0, 0x1a3, 6, 1);
2252 for (lane = 0; lane < 8; lane++) {
2253 if (state[lane] == COMPLETE) {
2254 timings[reg_178][channel][slot][rank][lane].
2255 smallest =
2256 lower_usable[lane] +
2257 (info->training.
2258 lane_timings[0][channel][slot][rank][lane]
2259 & 0x3F) - 32;
2260 timings[reg_178][channel][slot][rank][lane].
2261 largest =
2262 upper_usable[lane] +
2263 (info->training.
2264 lane_timings[0][channel][slot][rank][lane]
2265 & 0x3F) - 32;
2266 }
2267 }
2268 }
2269
2270 if (!first_run) {
2271 for (lane = 0; lane < 8; lane++)
2272 if (state[lane] == COMPLETE) {
2273 write_500(info, channel,
2274 timings[reg_178][channel][slot][rank]
2275 [lane].smallest,
2276 get_timing_register_addr(lane, 0,
2277 slot, rank),
2278 9, 1);
2279 write_500(info, channel,
2280 timings[reg_178][channel][slot][rank]
2281 [lane].smallest +
2282 info->training.
2283 lane_timings[1][channel][slot][rank]
2284 [lane]
2285 -
2286 info->training.
2287 lane_timings[0][channel][slot][rank]
2288 [lane], get_timing_register_addr(lane,
2289 1,
2290 slot,
2291 rank),
2292 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002293 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002294 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002295 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296
2297 do {
2298 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002299 for (i = 0; i < niter; i++) {
2300 if (failmask == 0xFF)
2301 break;
2302 failmask |=
2303 check_testing_type2(info, total_rank, 2, i,
2304 0);
2305 failmask |=
2306 check_testing_type2(info, total_rank, 3, i,
2307 1);
2308 }
Felix Held04be2dd2018-07-29 04:53:22 +02002309 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002310 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002311 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002312 if ((1 << lane) & failmask) {
2313 if (timings[reg_178][channel]
2314 [slot][rank][lane].
2315 largest <=
2316 timings[reg_178][channel]
2317 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002318 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002319 [lane] = -1;
2320 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002321 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 [lane] = 0;
2323 timings[reg_178]
2324 [channel][slot]
2325 [rank][lane].
2326 smallest++;
2327 write_500(info, channel,
2328 timings
2329 [reg_178]
2330 [channel]
2331 [slot][rank]
2332 [lane].
2333 smallest,
2334 get_timing_register_addr
2335 (lane, 0,
2336 slot, rank),
2337 9, 1);
2338 write_500(info, channel,
2339 timings
2340 [reg_178]
2341 [channel]
2342 [slot][rank]
2343 [lane].
2344 smallest +
2345 info->
2346 training.
2347 lane_timings
2348 [1][channel]
2349 [slot][rank]
2350 [lane]
2351 -
2352 info->
2353 training.
2354 lane_timings
2355 [0][channel]
2356 [slot][rank]
2357 [lane],
2358 get_timing_register_addr
2359 (lane, 1,
2360 slot, rank),
2361 9, 1);
2362 }
2363 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002364 num_successfully_checked[lane]
2365 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002366 }
2367 }
Felix Held04be2dd2018-07-29 04:53:22 +02002368 while (!check_bounded(num_successfully_checked, 2))
2369 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002370
2371 for (lane = 0; lane < 8; lane++)
2372 if (state[lane] == COMPLETE) {
2373 write_500(info, channel,
2374 timings[reg_178][channel][slot][rank]
2375 [lane].largest,
2376 get_timing_register_addr(lane, 0,
2377 slot, rank),
2378 9, 1);
2379 write_500(info, channel,
2380 timings[reg_178][channel][slot][rank]
2381 [lane].largest +
2382 info->training.
2383 lane_timings[1][channel][slot][rank]
2384 [lane]
2385 -
2386 info->training.
2387 lane_timings[0][channel][slot][rank]
2388 [lane], get_timing_register_addr(lane,
2389 1,
2390 slot,
2391 rank),
2392 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002393 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002394 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002395 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002396
2397 do {
2398 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399 for (i = 0; i < niter; i++) {
2400 if (failmask == 0xFF)
2401 break;
2402 failmask |=
2403 check_testing_type2(info, total_rank, 2, i,
2404 0);
2405 failmask |=
2406 check_testing_type2(info, total_rank, 3, i,
2407 1);
2408 }
2409
Felix Held04be2dd2018-07-29 04:53:22 +02002410 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002411 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002412 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002413 if ((1 << lane) & failmask) {
2414 if (timings[reg_178][channel]
2415 [slot][rank][lane].
2416 largest <=
2417 timings[reg_178][channel]
2418 [slot][rank][lane].
2419 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002420 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 [lane] = -1;
2422 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002423 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002424 [lane] = 0;
2425 timings[reg_178]
2426 [channel][slot]
2427 [rank][lane].
2428 largest--;
2429 write_500(info, channel,
2430 timings
2431 [reg_178]
2432 [channel]
2433 [slot][rank]
2434 [lane].
2435 largest,
2436 get_timing_register_addr
2437 (lane, 0,
2438 slot, rank),
2439 9, 1);
2440 write_500(info, channel,
2441 timings
2442 [reg_178]
2443 [channel]
2444 [slot][rank]
2445 [lane].
2446 largest +
2447 info->
2448 training.
2449 lane_timings
2450 [1][channel]
2451 [slot][rank]
2452 [lane]
2453 -
2454 info->
2455 training.
2456 lane_timings
2457 [0][channel]
2458 [slot][rank]
2459 [lane],
2460 get_timing_register_addr
2461 (lane, 1,
2462 slot, rank),
2463 9, 1);
2464 }
2465 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002466 num_successfully_checked[lane]
2467 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002468 }
2469 }
2470 }
Felix Held04be2dd2018-07-29 04:53:22 +02002471 while (!check_bounded(num_successfully_checked, 3))
2472 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002473
2474 for (lane = 0; lane < 8; lane++) {
2475 write_500(info, channel,
2476 info->training.
2477 lane_timings[0][channel][slot][rank][lane],
2478 get_timing_register_addr(lane, 0, slot, rank),
2479 9, 1);
2480 write_500(info, channel,
2481 info->training.
2482 lane_timings[1][channel][slot][rank][lane],
2483 get_timing_register_addr(lane, 1, slot, rank),
2484 9, 1);
2485 if (timings[reg_178][channel][slot][rank][lane].
2486 largest <=
2487 timings[reg_178][channel][slot][rank][lane].
2488 smallest) {
2489 timings[reg_178][channel][slot][rank][lane].
2490 largest = 0;
2491 timings[reg_178][channel][slot][rank][lane].
2492 smallest = 0;
2493 }
2494 }
2495 }
2496}
2497
2498static void set_10b(struct raminfo *info, u8 val)
2499{
2500 int channel;
2501 int slot, rank;
2502 int lane;
2503
2504 if (read_1d0(0x10b, 6) == val)
2505 return;
2506
2507 write_1d0(val, 0x10b, 6, 1);
2508
2509 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2510 u16 reg_500;
2511 reg_500 = read_500(info, channel,
2512 get_timing_register_addr(lane, 0, slot,
2513 rank), 9);
2514 if (val == 1) {
2515 if (lut16[info->clock_speed_index] <= reg_500)
2516 reg_500 -= lut16[info->clock_speed_index];
2517 else
2518 reg_500 = 0;
2519 } else {
2520 reg_500 += lut16[info->clock_speed_index];
2521 }
2522 write_500(info, channel, reg_500,
2523 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2524 }
2525}
2526
2527static void set_ecc(int onoff)
2528{
2529 int channel;
2530 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2531 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002532 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002533 if (onoff)
2534 t |= 1;
2535 else
2536 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002537 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002538 }
2539}
2540
2541static void set_178(u8 val)
2542{
2543 if (val >= 31)
2544 val = val - 31;
2545 else
2546 val = 63 - val;
2547
2548 write_1d0(2 * val, 0x178, 7, 1);
2549}
2550
2551static void
2552write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2553 int type)
2554{
2555 int lane;
2556
2557 for (lane = 0; lane < 8; lane++)
2558 write_500(info, channel,
2559 info->training.
2560 lane_timings[type][channel][slot][rank][lane],
2561 get_timing_register_addr(lane, type, slot, rank), 9,
2562 0);
2563}
2564
2565static void
2566try_timing_offsets(struct raminfo *info, int channel,
2567 int slot, int rank, int totalrank)
2568{
2569 u16 count[8];
2570 enum state state[8];
2571 u8 lower_usable[8], upper_usable[8];
2572 int lane;
2573 int i;
2574 int flip = 1;
2575 int timing_offset;
2576
2577 for (i = 0; i < 8; i++)
2578 state[i] = BEFORE_USABLE;
2579
2580 memset(count, 0, sizeof(count));
2581
2582 for (lane = 0; lane < 8; lane++)
2583 write_500(info, channel,
2584 info->training.
2585 lane_timings[2][channel][slot][rank][lane] + 32,
2586 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2587
2588 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2589 timing_offset++) {
2590 u8 failmask;
2591 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2592 failmask = 0;
2593 for (i = 0; i < 2 && failmask != 0xff; i++) {
2594 flip = !flip;
2595 write_testing(info, totalrank, flip);
2596 failmask |= check_testing(info, totalrank, flip);
2597 }
2598 do_fsm(state, count, failmask, 10, 63, lower_usable,
2599 upper_usable, timing_offset);
2600 }
2601 write_1d0(0, 0x1bb, 6, 1);
2602 dump_timings(info);
2603 if (!validate_state(state))
2604 die("Couldn't discover DRAM timings (1)\n");
2605
2606 for (lane = 0; lane < 8; lane++) {
2607 u8 bias = 0;
2608
2609 if (info->silicon_revision) {
2610 int usable_length;
2611
2612 usable_length = upper_usable[lane] - lower_usable[lane];
2613 if (usable_length >= 20) {
2614 bias = usable_length / 2 - 10;
2615 if (bias >= 2)
2616 bias = 2;
2617 }
2618 }
2619 write_500(info, channel,
2620 info->training.
2621 lane_timings[2][channel][slot][rank][lane] +
2622 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2623 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2624 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2625 info->training.lane_timings[2][channel][slot][rank][lane] +
2626 lower_usable[lane];
2627 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2628 info->training.lane_timings[2][channel][slot][rank][lane] +
2629 upper_usable[lane];
2630 info->training.timing2_offset[channel][slot][rank][lane] =
2631 info->training.lane_timings[2][channel][slot][rank][lane];
2632 }
2633}
2634
2635static u8
2636choose_training(struct raminfo *info, int channel, int slot, int rank,
2637 int lane, timing_bounds_t * timings, u8 center_178)
2638{
2639 u16 central_weight;
2640 u16 side_weight;
2641 unsigned int sum = 0, count = 0;
2642 u8 span;
2643 u8 lower_margin, upper_margin;
2644 u8 reg_178;
2645 u8 result;
2646
2647 span = 12;
2648 central_weight = 20;
2649 side_weight = 20;
2650 if (info->silicon_revision == 1 && channel == 1) {
2651 central_weight = 5;
2652 side_weight = 20;
2653 if ((info->
2654 populated_ranks_mask[1] ^ (info->
2655 populated_ranks_mask[1] >> 2)) &
2656 1)
2657 span = 18;
2658 }
2659 if ((info->populated_ranks_mask[0] & 5) == 5) {
2660 central_weight = 20;
2661 side_weight = 20;
2662 }
2663 if (info->clock_speed_index >= 2
2664 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2665 if (info->silicon_revision == 1) {
2666 switch (channel) {
2667 case 0:
2668 if (lane == 1) {
2669 central_weight = 10;
2670 side_weight = 20;
2671 }
2672 break;
2673 case 1:
2674 if (lane == 6) {
2675 side_weight = 5;
2676 central_weight = 20;
2677 }
2678 break;
2679 }
2680 }
2681 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2682 side_weight = 5;
2683 central_weight = 20;
2684 }
2685 }
2686 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2687 reg_178 += span) {
2688 u8 smallest;
2689 u8 largest;
2690 largest = timings[reg_178][channel][slot][rank][lane].largest;
2691 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2692 if (largest - smallest + 1 >= 5) {
2693 unsigned int weight;
2694 if (reg_178 == center_178)
2695 weight = central_weight;
2696 else
2697 weight = side_weight;
2698 sum += weight * (largest + smallest);
2699 count += weight;
2700 }
2701 }
2702 dump_timings(info);
2703 if (count == 0)
2704 die("Couldn't discover DRAM timings (2)\n");
2705 result = sum / (2 * count);
2706 lower_margin =
2707 result - timings[center_178][channel][slot][rank][lane].smallest;
2708 upper_margin =
2709 timings[center_178][channel][slot][rank][lane].largest - result;
2710 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002711 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002712 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002713 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002714 return result;
2715}
2716
2717#define STANDARD_MIN_MARGIN 5
2718
2719static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2720{
2721 u16 margin[64];
2722 int lane, rank, slot, channel;
2723 u8 reg178;
2724 int count = 0, sum = 0;
2725
2726 for (reg178 = reg178_min[info->clock_speed_index];
2727 reg178 < reg178_max[info->clock_speed_index];
2728 reg178 += reg178_step[info->clock_speed_index]) {
2729 margin[reg178] = -1;
2730 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2731 int curmargin =
2732 timings[reg178][channel][slot][rank][lane].largest -
2733 timings[reg178][channel][slot][rank][lane].
2734 smallest + 1;
2735 if (curmargin < margin[reg178])
2736 margin[reg178] = curmargin;
2737 }
2738 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2739 u16 weight;
2740 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2741 sum += weight * reg178;
2742 count += weight;
2743 }
2744 }
2745 dump_timings(info);
2746 if (count == 0)
2747 die("Couldn't discover DRAM timings (3)\n");
2748
2749 u8 threshold;
2750
2751 for (threshold = 30; threshold >= 5; threshold--) {
2752 int usable_length = 0;
2753 int smallest_fount = 0;
2754 for (reg178 = reg178_min[info->clock_speed_index];
2755 reg178 < reg178_max[info->clock_speed_index];
2756 reg178 += reg178_step[info->clock_speed_index])
2757 if (margin[reg178] >= threshold) {
2758 usable_length +=
2759 reg178_step[info->clock_speed_index];
2760 info->training.reg178_largest =
2761 reg178 -
2762 2 * reg178_step[info->clock_speed_index];
2763
2764 if (!smallest_fount) {
2765 smallest_fount = 1;
2766 info->training.reg178_smallest =
2767 reg178 +
2768 reg178_step[info->
2769 clock_speed_index];
2770 }
2771 }
2772 if (usable_length >= 0x21)
2773 break;
2774 }
2775
2776 return sum / count;
2777}
2778
2779static int check_cached_sanity(struct raminfo *info)
2780{
2781 int lane;
2782 int slot, rank;
2783 int channel;
2784
2785 if (!info->cached_training)
2786 return 0;
2787
2788 for (channel = 0; channel < NUM_CHANNELS; channel++)
2789 for (slot = 0; slot < NUM_SLOTS; slot++)
2790 for (rank = 0; rank < NUM_RANKS; rank++)
2791 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2792 u16 cached_value, estimation_value;
2793 cached_value =
2794 info->cached_training->
2795 lane_timings[1][channel][slot][rank]
2796 [lane];
2797 if (cached_value >= 0x18
2798 && cached_value <= 0x1E7) {
2799 estimation_value =
2800 info->training.
2801 lane_timings[1][channel]
2802 [slot][rank][lane];
2803 if (estimation_value <
2804 cached_value - 24)
2805 return 0;
2806 if (estimation_value >
2807 cached_value + 24)
2808 return 0;
2809 }
2810 }
2811 return 1;
2812}
2813
2814static int try_cached_training(struct raminfo *info)
2815{
2816 u8 saved_243[2];
2817 u8 tm;
2818
2819 int channel, slot, rank, lane;
2820 int flip = 1;
2821 int i, j;
2822
2823 if (!check_cached_sanity(info))
2824 return 0;
2825
2826 info->training.reg178_center = info->cached_training->reg178_center;
2827 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2828 info->training.reg178_largest = info->cached_training->reg178_largest;
2829 memcpy(&info->training.timing_bounds,
2830 &info->cached_training->timing_bounds,
2831 sizeof(info->training.timing_bounds));
2832 memcpy(&info->training.timing_offset,
2833 &info->cached_training->timing_offset,
2834 sizeof(info->training.timing_offset));
2835
2836 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002837 saved_243[0] = MCHBAR8(0x243);
2838 saved_243[1] = MCHBAR8(0x643);
2839 MCHBAR8(0x243) = saved_243[0] | 2;
2840 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002841 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002842 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002843 if (read_1d0(0x10b, 6) & 1)
2844 set_10b(info, 0);
2845 for (tm = 0; tm < 2; tm++) {
2846 int totalrank;
2847
2848 set_178(tm ? info->cached_training->reg178_largest : info->
2849 cached_training->reg178_smallest);
2850
2851 totalrank = 0;
2852 /* Check timing ranges. With i == 0 we check smallest one and with
2853 i == 1 the largest bound. With j == 0 we check that on the bound
2854 it still works whereas with j == 1 we check that just outside of
2855 bound we fail.
2856 */
2857 FOR_POPULATED_RANKS_BACKWARDS {
2858 for (i = 0; i < 2; i++) {
2859 for (lane = 0; lane < 8; lane++) {
2860 write_500(info, channel,
2861 info->cached_training->
2862 timing2_bounds[channel][slot]
2863 [rank][lane][i],
2864 get_timing_register_addr(lane,
2865 3,
2866 slot,
2867 rank),
2868 9, 1);
2869
2870 if (!i)
2871 write_500(info, channel,
2872 info->
2873 cached_training->
2874 timing2_offset
2875 [channel][slot][rank]
2876 [lane],
2877 get_timing_register_addr
2878 (lane, 2, slot, rank),
2879 9, 1);
2880 write_500(info, channel,
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].smallest,
2888 get_timing_register_addr(lane,
2889 0,
2890 slot,
2891 rank),
2892 9, 1);
2893 write_500(info, channel,
2894 info->cached_training->
2895 timing_offset[channel][slot]
2896 [rank][lane] +
2897 (i ? info->cached_training->
2898 timing_bounds[tm][channel]
2899 [slot][rank][lane].
2900 largest : info->
2901 cached_training->
2902 timing_bounds[tm][channel]
2903 [slot][rank][lane].
2904 smallest) - 64,
2905 get_timing_register_addr(lane,
2906 1,
2907 slot,
2908 rank),
2909 9, 1);
2910 }
2911 for (j = 0; j < 2; j++) {
2912 u8 failmask;
2913 u8 expected_failmask;
2914 char reg1b3;
2915
2916 reg1b3 = (j == 1) + 4;
2917 reg1b3 =
2918 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2919 write_1d0(reg1b3, 0x1bb, 6, 1);
2920 write_1d0(reg1b3, 0x1b3, 6, 1);
2921 write_1d0(reg1b3, 0x1a3, 6, 1);
2922
2923 flip = !flip;
2924 write_testing(info, totalrank, flip);
2925 failmask =
2926 check_testing(info, totalrank,
2927 flip);
2928 expected_failmask =
2929 j == 0 ? 0x00 : 0xff;
2930 if (failmask != expected_failmask)
2931 goto fail;
2932 }
2933 }
2934 totalrank++;
2935 }
2936 }
2937
2938 set_178(info->cached_training->reg178_center);
2939 if (info->use_ecc)
2940 set_ecc(1);
2941 write_training_data(info);
2942 write_1d0(0, 322, 3, 1);
2943 info->training = *info->cached_training;
2944
2945 write_1d0(0, 0x1bb, 6, 1);
2946 write_1d0(0, 0x1b3, 6, 1);
2947 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002948 MCHBAR8(0x243) = saved_243[0];
2949 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002950
2951 return 1;
2952
2953fail:
2954 FOR_POPULATED_RANKS {
2955 write_500_timings_type(info, channel, slot, rank, 1);
2956 write_500_timings_type(info, channel, slot, rank, 2);
2957 write_500_timings_type(info, channel, slot, rank, 3);
2958 }
2959
2960 write_1d0(0, 0x1bb, 6, 1);
2961 write_1d0(0, 0x1b3, 6, 1);
2962 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002963 MCHBAR8(0x243) = saved_243[0];
2964 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002965
2966 return 0;
2967}
2968
2969static void do_ram_training(struct raminfo *info)
2970{
2971 u8 saved_243[2];
2972 int totalrank = 0;
2973 u8 reg_178;
2974 int niter;
2975
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002976 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002977 int lane, rank, slot, channel;
2978 u8 reg178_center;
2979
2980 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002981 saved_243[0] = MCHBAR8(0x243);
2982 saved_243[1] = MCHBAR8(0x643);
2983 MCHBAR8(0x243) = saved_243[0] | 2;
2984 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002985 switch (info->clock_speed_index) {
2986 case 0:
2987 niter = 5;
2988 break;
2989 case 1:
2990 niter = 10;
2991 break;
2992 default:
2993 niter = 19;
2994 break;
2995 }
2996 set_ecc(0);
2997
2998 FOR_POPULATED_RANKS_BACKWARDS {
2999 int i;
3000
3001 write_500_timings_type(info, channel, slot, rank, 0);
3002
3003 write_testing(info, totalrank, 0);
3004 for (i = 0; i < niter; i++) {
3005 write_testing_type2(info, totalrank, 2, i, 0);
3006 write_testing_type2(info, totalrank, 3, i, 1);
3007 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003008 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003009 totalrank++;
3010 }
3011
3012 if (reg178_min[info->clock_speed_index] <
3013 reg178_max[info->clock_speed_index])
3014 memset(timings[reg178_min[info->clock_speed_index]], 0,
3015 sizeof(timings[0]) *
3016 (reg178_max[info->clock_speed_index] -
3017 reg178_min[info->clock_speed_index]));
3018 for (reg_178 = reg178_min[info->clock_speed_index];
3019 reg_178 < reg178_max[info->clock_speed_index];
3020 reg_178 += reg178_step[info->clock_speed_index]) {
3021 totalrank = 0;
3022 set_178(reg_178);
3023 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3024 for (slot = 0; slot < NUM_SLOTS; slot++)
3025 for (rank = 0; rank < NUM_RANKS; rank++) {
3026 memset(&timings[reg_178][channel][slot]
3027 [rank][0].smallest, 0, 16);
3028 if (info->
3029 populated_ranks[channel][slot]
3030 [rank]) {
3031 train_ram_at_178(info, channel,
3032 slot, rank,
3033 totalrank,
3034 reg_178, 1,
3035 niter,
3036 timings);
3037 totalrank++;
3038 }
3039 }
3040 }
3041
3042 reg178_center = choose_reg178(info, timings);
3043
3044 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3045 info->training.timing_bounds[0][channel][slot][rank][lane].
3046 smallest =
3047 timings[info->training.
3048 reg178_smallest][channel][slot][rank][lane].
3049 smallest;
3050 info->training.timing_bounds[0][channel][slot][rank][lane].
3051 largest =
3052 timings[info->training.
3053 reg178_smallest][channel][slot][rank][lane].largest;
3054 info->training.timing_bounds[1][channel][slot][rank][lane].
3055 smallest =
3056 timings[info->training.
3057 reg178_largest][channel][slot][rank][lane].smallest;
3058 info->training.timing_bounds[1][channel][slot][rank][lane].
3059 largest =
3060 timings[info->training.
3061 reg178_largest][channel][slot][rank][lane].largest;
3062 info->training.timing_offset[channel][slot][rank][lane] =
3063 info->training.lane_timings[1][channel][slot][rank][lane]
3064 -
3065 info->training.lane_timings[0][channel][slot][rank][lane] +
3066 64;
3067 }
3068
3069 if (info->silicon_revision == 1
3070 && (info->
3071 populated_ranks_mask[1] ^ (info->
3072 populated_ranks_mask[1] >> 2)) & 1) {
3073 int ranks_after_channel1;
3074
3075 totalrank = 0;
3076 for (reg_178 = reg178_center - 18;
3077 reg_178 <= reg178_center + 18; reg_178 += 18) {
3078 totalrank = 0;
3079 set_178(reg_178);
3080 for (slot = 0; slot < NUM_SLOTS; slot++)
3081 for (rank = 0; rank < NUM_RANKS; rank++) {
3082 if (info->
3083 populated_ranks[1][slot][rank]) {
3084 train_ram_at_178(info, 1, slot,
3085 rank,
3086 totalrank,
3087 reg_178, 0,
3088 niter,
3089 timings);
3090 totalrank++;
3091 }
3092 }
3093 }
3094 ranks_after_channel1 = totalrank;
3095
3096 for (reg_178 = reg178_center - 12;
3097 reg_178 <= reg178_center + 12; reg_178 += 12) {
3098 totalrank = ranks_after_channel1;
3099 set_178(reg_178);
3100 for (slot = 0; slot < NUM_SLOTS; slot++)
3101 for (rank = 0; rank < NUM_RANKS; rank++)
3102 if (info->
3103 populated_ranks[0][slot][rank]) {
3104 train_ram_at_178(info, 0, slot,
3105 rank,
3106 totalrank,
3107 reg_178, 0,
3108 niter,
3109 timings);
3110 totalrank++;
3111 }
3112
3113 }
3114 } else {
3115 for (reg_178 = reg178_center - 12;
3116 reg_178 <= reg178_center + 12; reg_178 += 12) {
3117 totalrank = 0;
3118 set_178(reg_178);
3119 FOR_POPULATED_RANKS_BACKWARDS {
3120 train_ram_at_178(info, channel, slot, rank,
3121 totalrank, reg_178, 0, niter,
3122 timings);
3123 totalrank++;
3124 }
3125 }
3126 }
3127
3128 set_178(reg178_center);
3129 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3130 u16 tm0;
3131
3132 tm0 =
3133 choose_training(info, channel, slot, rank, lane, timings,
3134 reg178_center);
3135 write_500(info, channel, tm0,
3136 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3137 write_500(info, channel,
3138 tm0 +
3139 info->training.
3140 lane_timings[1][channel][slot][rank][lane] -
3141 info->training.
3142 lane_timings[0][channel][slot][rank][lane],
3143 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3144 }
3145
3146 totalrank = 0;
3147 FOR_POPULATED_RANKS_BACKWARDS {
3148 try_timing_offsets(info, channel, slot, rank, totalrank);
3149 totalrank++;
3150 }
Felix Held04be2dd2018-07-29 04:53:22 +02003151 MCHBAR8(0x243) = saved_243[0];
3152 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003153 write_1d0(0, 0x142, 3, 1);
3154 info->training.reg178_center = reg178_center;
3155}
3156
3157static void ram_training(struct raminfo *info)
3158{
3159 u16 saved_fc4;
3160
Felix Held04be2dd2018-07-29 04:53:22 +02003161 saved_fc4 = MCHBAR16(0xfc4);
3162 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003163
3164 if (info->revision >= 8)
3165 read_4090(info);
3166
3167 if (!try_cached_training(info))
3168 do_ram_training(info);
3169 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3170 && info->clock_speed_index < 2)
3171 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003172 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003173}
3174
Martin Roth468d02c2019-10-23 21:44:42 -06003175static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003176{
Martin Roth468d02c2019-10-23 21:44:42 -06003177 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003178 if (a > b) {
3179 t = a;
3180 a = b;
3181 b = t;
3182 }
3183 /* invariant a < b. */
3184 while (a) {
3185 t = b % a;
3186 b = a;
3187 a = t;
3188 }
3189 return b;
3190}
3191
3192static inline int div_roundup(int a, int b)
3193{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003194 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195}
3196
Martin Roth468d02c2019-10-23 21:44:42 -06003197static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003198{
3199 return (a * b) / gcd(a, b);
3200}
3201
3202struct stru1 {
3203 u8 freqs_reversed;
3204 u8 freq_diff_reduced;
3205 u8 freq_min_reduced;
3206 u8 divisor_f4_to_fmax;
3207 u8 divisor_f3_to_fmax;
3208 u8 freq4_to_max_remainder;
3209 u8 freq3_to_2_remainder;
3210 u8 freq3_to_2_remaindera;
3211 u8 freq4_to_2_remainder;
3212 int divisor_f3_to_f1, divisor_f4_to_f2;
3213 int common_time_unit_ps;
3214 int freq_max_reduced;
3215};
3216
3217static void
3218compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3219 int num_cycles_2, int num_cycles_1, int round_it,
3220 int add_freqs, struct stru1 *result)
3221{
3222 int g;
3223 int common_time_unit_ps;
3224 int freq1_reduced, freq2_reduced;
3225 int freq_min_reduced;
3226 int freq_max_reduced;
3227 int freq3, freq4;
3228
3229 g = gcd(freq1, freq2);
3230 freq1_reduced = freq1 / g;
3231 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003232 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3233 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003234
3235 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3236 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3237 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3238 if (add_freqs) {
3239 freq3 += freq2_reduced;
3240 freq4 += freq1_reduced;
3241 }
3242
3243 if (round_it) {
3244 result->freq3_to_2_remainder = 0;
3245 result->freq3_to_2_remaindera = 0;
3246 result->freq4_to_max_remainder = 0;
3247 result->divisor_f4_to_f2 = 0;
3248 result->divisor_f3_to_f1 = 0;
3249 } else {
3250 if (freq2_reduced < freq1_reduced) {
3251 result->freq3_to_2_remainder =
3252 result->freq3_to_2_remaindera =
3253 freq3 % freq1_reduced - freq1_reduced + 1;
3254 result->freq4_to_max_remainder =
3255 -(freq4 % freq1_reduced);
3256 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3257 result->divisor_f4_to_f2 =
3258 (freq4 -
3259 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3260 result->freq4_to_2_remainder =
3261 -(char)((freq1_reduced - freq2_reduced) +
3262 ((u8) freq4 -
3263 (freq1_reduced -
3264 freq2_reduced)) % (u8) freq2_reduced);
3265 } else {
3266 if (freq2_reduced > freq1_reduced) {
3267 result->freq4_to_max_remainder =
3268 (freq4 % freq2_reduced) - freq2_reduced + 1;
3269 result->freq4_to_2_remainder =
3270 freq4 % freq_max_reduced -
3271 freq_max_reduced + 1;
3272 } else {
3273 result->freq4_to_max_remainder =
3274 -(freq4 % freq2_reduced);
3275 result->freq4_to_2_remainder =
3276 -(char)(freq4 % freq_max_reduced);
3277 }
3278 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3279 result->divisor_f3_to_f1 =
3280 (freq3 -
3281 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3282 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3283 result->freq3_to_2_remaindera =
3284 -(char)((freq_max_reduced - freq_min_reduced) +
3285 (freq3 -
3286 (freq_max_reduced -
3287 freq_min_reduced)) % freq1_reduced);
3288 }
3289 }
3290 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3291 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3292 if (round_it) {
3293 if (freq2_reduced > freq1_reduced) {
3294 if (freq3 % freq_max_reduced)
3295 result->divisor_f3_to_fmax++;
3296 }
3297 if (freq2_reduced < freq1_reduced) {
3298 if (freq4 % freq_max_reduced)
3299 result->divisor_f4_to_fmax++;
3300 }
3301 }
3302 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3303 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3304 result->freq_min_reduced = freq_min_reduced;
3305 result->common_time_unit_ps = common_time_unit_ps;
3306 result->freq_max_reduced = freq_max_reduced;
3307}
3308
3309static void
3310set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3311 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3312 int num_cycles_4, int reverse)
3313{
3314 struct stru1 vv;
3315 char multiplier;
3316
3317 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3318 0, 1, &vv);
3319
3320 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003321 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003322 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3323 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3324 div_roundup(num_cycles_1,
3325 vv.common_time_unit_ps) +
3326 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3327 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3328
3329 u32 y =
3330 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3331 vv.freq_max_reduced * multiplier)
3332 | (vv.
3333 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3334 multiplier) << 16) | ((u8) (vv.
3335 freq_min_reduced
3336 *
3337 multiplier)
3338 << 24);
3339 u32 x =
3340 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3341 divisor_f3_to_f1
3342 << 16)
3343 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3344 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003345 MCHBAR32(reg) = y;
3346 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003347 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003348 MCHBAR32(reg + 4) = y;
3349 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003350 }
3351}
3352
3353static void
3354set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3355 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3356 int num_cycles_4)
3357{
3358 struct stru1 ratios1;
3359 struct stru1 ratios2;
3360
3361 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3362 0, 1, &ratios2);
3363 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3364 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003365 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003366 ratios1.freq4_to_max_remainder | (ratios2.
3367 freq4_to_max_remainder
3368 << 8)
3369 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3370 divisor_f4_to_fmax
3371 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003372 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3373 (ratios2.freq4_to_max_remainder << 8) |
3374 (ratios1.divisor_f4_to_fmax << 16) |
3375 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003376}
3377
3378static void
3379set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3380 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3381{
3382 struct stru1 ratios;
3383
3384 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3385 round_it, add_freqs, &ratios);
3386 switch (mode) {
3387 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003388 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3389 (ratios.freqs_reversed << 8);
3390 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3391 (ratios.freq4_to_max_remainder << 8) |
3392 (ratios.divisor_f3_to_fmax << 16) |
3393 (ratios.divisor_f4_to_fmax << 20) |
3394 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003395 break;
3396
3397 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003398 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3399 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003400 break;
3401
3402 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003403 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3404 (ratios.freq4_to_max_remainder << 8) |
3405 (ratios.divisor_f3_to_fmax << 16) |
3406 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003407 break;
3408
3409 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003410 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3411 (ratios.divisor_f4_to_fmax << 8) |
3412 (ratios.freqs_reversed << 12) |
3413 (ratios.freq_min_reduced << 16) |
3414 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003415 break;
3416 }
3417}
3418
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003419static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003420{
3421 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3422 0, 1);
3423 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3424 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3425 1);
3426 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3427 frequency_11(info), 1231, 1524, 0, 1);
3428 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3429 frequency_11(info) / 2, 1278, 2008, 0, 1);
3430 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3431 1167, 1539, 0, 1);
3432 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3433 frequency_11(info) / 2, 1403, 1318, 0, 1);
3434 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3435 1);
3436 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3437 1);
3438 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3439 1, 1);
3440 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3441 1);
3442 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3443 frequency_11(info) / 2, 4000, 0, 0, 0);
3444 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3445 frequency_11(info) / 2, 4000, 4000, 0, 0);
3446
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003447 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003448 printk(RAM_SPEW, "[6dc] <= %x\n",
3449 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003450 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003451 } else
3452 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3453 info->delay46_ps[0], 0,
3454 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003455 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3456 frequency_11(info), 2500, 0, 0, 0);
3457 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3458 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003459 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003460 printk(RAM_SPEW, "[6e8] <= %x\n",
3461 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003462 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003463 } else
3464 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3465 info->delay46_ps[1], 0,
3466 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003467 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3468 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3469 470, 0);
3470 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3471 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3472 454, 459, 0);
3473 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3474 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3475 2588, 0);
3476 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3477 2405, 0);
3478 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3479 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3480 480, 0);
3481 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003482 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3483 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003484}
3485
3486static u16 get_max_timing(struct raminfo *info, int channel)
3487{
3488 int slot, rank, lane;
3489 u16 ret = 0;
3490
Felix Held04be2dd2018-07-29 04:53:22 +02003491 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003492 return 384;
3493
3494 if (info->revision < 8)
3495 return 256;
3496
3497 for (slot = 0; slot < NUM_SLOTS; slot++)
3498 for (rank = 0; rank < NUM_RANKS; rank++)
3499 if (info->populated_ranks[channel][slot][rank])
3500 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003501 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003502 get_timing_register_addr
3503 (lane, 0, slot,
3504 rank), 9));
3505 return ret;
3506}
3507
3508static void set_274265(struct raminfo *info)
3509{
3510 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3511 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3512 int delay_e_over_cycle_ps;
3513 int cycletime_ps;
3514 int channel;
3515
3516 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003517 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003518 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3519 cycletime_ps =
3520 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3521 delay_d_ps =
3522 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3523 - info->some_delay_3_ps_rounded + 200;
3524 if (!
3525 ((info->silicon_revision == 0
3526 || info->silicon_revision == 1)
3527 && (info->revision >= 8)))
3528 delay_d_ps += halfcycle_ps(info) * 2;
3529 delay_d_ps +=
3530 halfcycle_ps(info) * (!info->revision_flag_1 +
3531 info->some_delay_2_halfcycles_ceil +
3532 2 * info->some_delay_1_cycle_floor +
3533 info->clock_speed_index +
3534 2 * info->cas_latency - 7 + 11);
3535 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3536
Felix Held04be2dd2018-07-29 04:53:22 +02003537 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3538 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3539 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003540 delay_d_ps += 650;
3541 delay_c_ps = delay_d_ps + 1800;
3542 if (delay_c_ps <= delay_a_ps)
3543 delay_e_ps = 0;
3544 else
3545 delay_e_ps =
3546 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3547 cycletime_ps);
3548
3549 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3550 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3551 delay_f_cycles =
3552 div_roundup(2500 - delay_e_over_cycle_ps,
3553 2 * halfcycle_ps(info));
3554 if (delay_f_cycles > delay_e_cycles) {
3555 info->delay46_ps[channel] = delay_e_ps;
3556 delay_e_cycles = 0;
3557 } else {
3558 info->delay46_ps[channel] =
3559 delay_e_over_cycle_ps +
3560 2 * halfcycle_ps(info) * delay_f_cycles;
3561 delay_e_cycles -= delay_f_cycles;
3562 }
3563
3564 if (info->delay46_ps[channel] < 2500) {
3565 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003566 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003567 }
3568 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3569 if (delay_b_ps <= delay_a_ps)
3570 delay_b_ps = 0;
3571 else
3572 delay_b_ps -= delay_a_ps;
3573 info->delay54_ps[channel] =
3574 cycletime_ps * div_roundup(delay_b_ps,
3575 cycletime_ps) -
3576 2 * halfcycle_ps(info) * delay_e_cycles;
3577 if (info->delay54_ps[channel] < 2500)
3578 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003579 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003580 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3581 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003582 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003583 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003584 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003585 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3586 4 * halfcycle_ps(info)) - 6;
3587 MCHBAR32((channel << 10) + 0x274) =
3588 info->training.reg274265[channel][1] |
3589 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003590 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003591 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3592 4 * halfcycle_ps(info)) + 1;
3593 MCHBAR16((channel << 10) + 0x265) =
3594 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003596 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003597 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598 else
Felix Held04be2dd2018-07-29 04:53:22 +02003599 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003600}
3601
3602static void restore_274265(struct raminfo *info)
3603{
3604 int channel;
3605
3606 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003607 MCHBAR32((channel << 10) + 0x274) =
3608 (info->cached_training->reg274265[channel][0] << 16) |
3609 info->cached_training->reg274265[channel][1];
3610 MCHBAR16((channel << 10) + 0x265) =
3611 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003613 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003614 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615 else
Felix Held04be2dd2018-07-29 04:53:22 +02003616 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617}
3618
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619static void dmi_setup(void)
3620{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003621 gav(read8(DEFAULT_DMIBAR + 0x254));
3622 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3623 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003624 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003626 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627
3628 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3629 DEFAULT_GPIOBASE | 0x38);
3630 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3631}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003633void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003636 u16 ggc;
3637 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
Felix Held04be2dd2018-07-29 04:53:22 +02003639 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3641 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003642 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003643 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645
3646 dmi_setup();
3647
Felix Held04be2dd2018-07-29 04:53:22 +02003648 MCHBAR16(0x1170) = 0xa880;
3649 MCHBAR8(0x11c1) = 0x1;
3650 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003651 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003653 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3654 /* 0 for 32MB */
3655 gfxsize = 0;
3656 }
3657
3658 ggc = 0xb00 | ((gfxsize + 5) << 4);
3659
Angel Pons16fe1e02020-07-22 16:12:33 +02003660 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661
3662 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003663 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
3665 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003666 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003667 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003668 MCHBAR16_OR(0x2c30, 0x200);
3669 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003670 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003671 pci_read_config8(GMA, 0x62); // = 0x2
3672 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003673 read8(DEFAULT_RCBA + 0x2318);
3674 write8(DEFAULT_RCBA + 0x2318, 0x47);
3675 read8(DEFAULT_RCBA + 0x2320);
3676 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 }
3678
Felix Heldf83d80b2018-07-29 05:30:30 +02003679 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680
Angel Pons16fe1e02020-07-22 16:12:33 +02003681 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003682 gav(read32(DEFAULT_RCBA + 0x3428));
3683 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003684}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003686void raminit(const int s3resume, const u8 *spd_addrmap)
3687{
Martin Roth468d02c2019-10-23 21:44:42 -06003688 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003689 int i;
3690 struct raminfo info;
3691 u8 x2ca8;
3692 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003693 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003694
Felix Held04be2dd2018-07-29 04:53:22 +02003695 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003696
3697 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3698
Angel Pons16fe1e02020-07-22 16:12:33 +02003699 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700
3701 memset(&info, 0x5a, sizeof(info));
3702
3703 info.last_500_command[0] = 0;
3704 info.last_500_command[1] = 0;
3705
3706 info.fsb_frequency = 135 * 2;
3707 info.board_lane_delay[0] = 0x14;
3708 info.board_lane_delay[1] = 0x07;
3709 info.board_lane_delay[2] = 0x07;
3710 info.board_lane_delay[3] = 0x08;
3711 info.board_lane_delay[4] = 0x56;
3712 info.board_lane_delay[5] = 0x04;
3713 info.board_lane_delay[6] = 0x04;
3714 info.board_lane_delay[7] = 0x05;
3715 info.board_lane_delay[8] = 0x10;
3716
3717 info.training.reg_178 = 0;
3718 info.training.reg_10b = 0;
3719
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003720 info.memory_reserved_for_heci_mb = 0;
3721
3722 /* before SPD */
3723 timestamp_add_now(101);
3724
Felix Held29a9c072018-07-29 01:34:45 +02003725 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003726 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727
3728 collect_system_info(&info);
3729
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003730 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3731
3732 info.use_ecc = 1;
3733 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003734 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003735 int v;
3736 int try;
3737 int addr;
3738 const u8 useful_addresses[] = {
3739 DEVICE_TYPE,
3740 MODULE_TYPE,
3741 DENSITY,
3742 RANKS_AND_DQ,
3743 MEMORY_BUS_WIDTH,
3744 TIMEBASE_DIVIDEND,
3745 TIMEBASE_DIVISOR,
3746 CYCLETIME,
3747 CAS_LATENCIES_LSB,
3748 CAS_LATENCIES_MSB,
3749 CAS_LATENCY_TIME,
3750 0x11, 0x12, 0x13, 0x14, 0x15,
3751 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3752 0x1c, 0x1d,
3753 THERMAL_AND_REFRESH,
3754 0x20,
3755 REFERENCE_RAW_CARD_USED,
3756 RANK1_ADDRESS_MAPPING,
3757 0x75, 0x76, 0x77, 0x78,
3758 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3759 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3760 0x85, 0x86, 0x87, 0x88,
3761 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3762 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3763 0x95
3764 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003765 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766 continue;
3767 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003768 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003769 DEVICE_TYPE);
3770 if (v >= 0)
3771 break;
3772 }
3773 if (v < 0)
3774 continue;
3775 for (addr = 0;
3776 addr <
3777 sizeof(useful_addresses) /
3778 sizeof(useful_addresses[0]); addr++)
3779 gav(info.
3780 spd[channel][0][useful_addresses
3781 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003782 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003783 useful_addresses
3784 [addr]));
3785 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3786 die("Only DDR3 is supported");
3787
3788 v = info.spd[channel][0][RANKS_AND_DQ];
3789 info.populated_ranks[channel][0][0] = 1;
3790 info.populated_ranks[channel][0][1] =
3791 ((v >> 3) & 7);
3792 if (((v >> 3) & 7) > 1)
3793 die("At most 2 ranks are supported");
3794 if ((v & 7) == 0 || (v & 7) > 2)
3795 die("Only x8 and x16 modules are supported");
3796 if ((info.
3797 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3798 && (info.
3799 spd[channel][slot][MODULE_TYPE] & 0xF)
3800 != 3)
3801 die("Registered memory is not supported");
3802 info.is_x16_module[channel][0] = (v & 7) - 1;
3803 info.density[channel][slot] =
3804 info.spd[channel][slot][DENSITY] & 0xF;
3805 if (!
3806 (info.
3807 spd[channel][slot][MEMORY_BUS_WIDTH] &
3808 0x18))
3809 info.use_ecc = 0;
3810 }
3811
3812 gav(0x55);
3813
3814 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3815 int v = 0;
3816 for (slot = 0; slot < NUM_SLOTS; slot++)
3817 for (rank = 0; rank < NUM_RANKS; rank++)
3818 v |= info.
3819 populated_ranks[channel][slot][rank]
3820 << (2 * slot + rank);
3821 info.populated_ranks_mask[channel] = v;
3822 }
3823
3824 gav(0x55);
3825
Angel Pons16fe1e02020-07-22 16:12:33 +02003826 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003827 }
3828
3829 /* after SPD */
3830 timestamp_add_now(102);
3831
Felix Held04be2dd2018-07-29 04:53:22 +02003832 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003833
3834 collect_system_info(&info);
3835 calculate_timings(&info);
3836
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003838 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003839 if (x2ca8 == 0 && (reg8 & 0x80)) {
3840 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3841 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3842 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3843 */
3844
3845 /* Clear bit7. */
3846
3847 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3848 (reg8 & ~(1 << 7)));
3849
3850 printk(BIOS_INFO,
3851 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003852 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003853 }
3854 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855
3856 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003857 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3858 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859
3860 compute_derived_timings(&info);
3861
3862 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003863 gav(MCHBAR8(0x164));
3864 MCHBAR8(0x164) = 0x26;
3865 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866 }
3867
Felix Held04be2dd2018-07-29 04:53:22 +02003868 MCHBAR32_OR(0x18b4, 0x210000);
3869 MCHBAR32_OR(0x1890, 0x2000000);
3870 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
Angel Ponsa457e352020-07-22 18:17:33 +02003872 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3873 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874
Felix Held04be2dd2018-07-29 04:53:22 +02003875 gav(MCHBAR16(0x2c10));
3876 MCHBAR16(0x2c10) = 0x412;
3877 gav(MCHBAR16(0x2c10));
3878 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879
Felix Held04be2dd2018-07-29 04:53:22 +02003880 gav(MCHBAR8(0x2ca8)); // !!!!
3881 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003882
Angel Ponsa457e352020-07-22 18:17:33 +02003883 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3884 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003885 gav(MCHBAR32(0x1c04)); // !!!!
3886 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887
3888 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003889 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003890 }
3891
Felix Held04be2dd2018-07-29 04:53:22 +02003892 MCHBAR32(0x18d8) = 0x120000;
3893 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003894 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003896 MCHBAR32(0x18d8) = 0x40000;
3897 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003898 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3899 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003900 MCHBAR32(0x18d8) = 0x180000;
3901 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003902 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3903 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003904 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905
Felix Held04be2dd2018-07-29 04:53:22 +02003906 gav(MCHBAR32(0x18dc)); // !!!!
3907 MCHBAR32(0x18dc) = 0x3;
3908 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003909
3910 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003911 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912 }
3913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003915 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003916 MCHBAR32(0x1a10) = 0x4200010e;
3917 MCHBAR32_OR(0x18b8, 0x200);
3918 gav(MCHBAR32(0x1918)); // !!!!
3919 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
Felix Held04be2dd2018-07-29 04:53:22 +02003921 gav(MCHBAR32(0x18b8)); // !!!!
3922 MCHBAR32(0x18b8) = 0xe00;
3923 gav(MCHBAR32(0x182c)); // !!!!
3924 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003925 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3926 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003927 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3928 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003929
Felix Held04be2dd2018-07-29 04:53:22 +02003930 MCHBAR32_AND(0x18b4, 0xffff7fff);
3931 gav(MCHBAR32(0x1a68)); // !!!!
3932 MCHBAR32(0x1a68) = 0x343800;
3933 gav(MCHBAR32(0x1e68)); // !!!!
3934 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935
3936 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
Angel Pons08143572020-07-22 17:47:06 +02003940 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3941 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3942 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3943 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3944 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003945 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3946 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003947 gav(MCHBAR32(0x1af0)); // !!!!
3948 gav(MCHBAR32(0x1af0)); // !!!!
3949 MCHBAR32(0x1af0) = 0x1f020003;
3950 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003951
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003952 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003953 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954 }
3955
Felix Held04be2dd2018-07-29 04:53:22 +02003956 gav(MCHBAR32(0x1890)); // !!!!
3957 MCHBAR32(0x1890) = 0x80102;
3958 gav(MCHBAR32(0x18b4)); // !!!!
3959 MCHBAR32(0x18b4) = 0x216000;
3960 MCHBAR32(0x18a4) = 0x22222222;
3961 MCHBAR32(0x18a8) = 0x22222222;
3962 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003963
3964 udelay(1000);
3965
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003966 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003968 if (x2ca8 == 0) {
3969 int j;
3970 if (s3resume && info.cached_training) {
3971 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003972 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003973 info.cached_training->reg2ca9_bit0);
3974 for (i = 0; i < 2; i++)
3975 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003976 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003977 i, j, info.cached_training->reg274265[i][j]);
3978 } else {
3979 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003980 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003981 info.training.reg2ca9_bit0);
3982 for (i = 0; i < 2; i++)
3983 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003984 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003985 i, j, info.training.reg274265[i][j]);
3986 }
3987
3988 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003989
3990 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003991 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003992 }
3993
3994 udelay(1000);
3995
3996 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003997 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003998 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003999 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4000 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4001 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004002
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004003 MCHBAR8(0x1150);
4004 MCHBAR8(0x1151);
4005 MCHBAR8(0x1022);
4006 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004007 MCHBAR32(0x1300) = 0x60606060;
4008 MCHBAR32(0x1304) = 0x60606060;
4009 MCHBAR32(0x1308) = 0x78797a7b;
4010 MCHBAR32(0x130c) = 0x7c7d7e7f;
4011 MCHBAR32(0x1310) = 0x60606060;
4012 MCHBAR32(0x1314) = 0x60606060;
4013 MCHBAR32(0x1318) = 0x60606060;
4014 MCHBAR32(0x131c) = 0x60606060;
4015 MCHBAR32(0x1320) = 0x50515253;
4016 MCHBAR32(0x1324) = 0x54555657;
4017 MCHBAR32(0x1328) = 0x58595a5b;
4018 MCHBAR32(0x132c) = 0x5c5d5e5f;
4019 MCHBAR32(0x1330) = 0x40414243;
4020 MCHBAR32(0x1334) = 0x44454647;
4021 MCHBAR32(0x1338) = 0x48494a4b;
4022 MCHBAR32(0x133c) = 0x4c4d4e4f;
4023 MCHBAR32(0x1340) = 0x30313233;
4024 MCHBAR32(0x1344) = 0x34353637;
4025 MCHBAR32(0x1348) = 0x38393a3b;
4026 MCHBAR32(0x134c) = 0x3c3d3e3f;
4027 MCHBAR32(0x1350) = 0x20212223;
4028 MCHBAR32(0x1354) = 0x24252627;
4029 MCHBAR32(0x1358) = 0x28292a2b;
4030 MCHBAR32(0x135c) = 0x2c2d2e2f;
4031 MCHBAR32(0x1360) = 0x10111213;
4032 MCHBAR32(0x1364) = 0x14151617;
4033 MCHBAR32(0x1368) = 0x18191a1b;
4034 MCHBAR32(0x136c) = 0x1c1d1e1f;
4035 MCHBAR32(0x1370) = 0x10203;
4036 MCHBAR32(0x1374) = 0x4050607;
4037 MCHBAR32(0x1378) = 0x8090a0b;
4038 MCHBAR32(0x137c) = 0xc0d0e0f;
4039 MCHBAR8(0x11cc) = 0x4e;
4040 MCHBAR32(0x1110) = 0x73970404;
4041 MCHBAR32(0x1114) = 0x72960404;
4042 MCHBAR32(0x1118) = 0x6f950404;
4043 MCHBAR32(0x111c) = 0x6d940404;
4044 MCHBAR32(0x1120) = 0x6a930404;
4045 MCHBAR32(0x1124) = 0x68a41404;
4046 MCHBAR32(0x1128) = 0x66a21404;
4047 MCHBAR32(0x112c) = 0x63a01404;
4048 MCHBAR32(0x1130) = 0x609e1404;
4049 MCHBAR32(0x1134) = 0x5f9c1404;
4050 MCHBAR32(0x1138) = 0x5c961404;
4051 MCHBAR32(0x113c) = 0x58a02404;
4052 MCHBAR32(0x1140) = 0x54942404;
4053 MCHBAR32(0x1190) = 0x900080a;
4054 MCHBAR16(0x11c0) = 0xc40b;
4055 MCHBAR16(0x11c2) = 0x303;
4056 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004057 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004058 MCHBAR32(0x11b8) = 0x70c3000;
4059 MCHBAR8(0x11ec) = 0xa;
4060 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004061 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004062 MCHBAR16(0x11ca) = 0xfa;
4063 MCHBAR32(0x11e4) = 0x4e20;
4064 MCHBAR8(0x11bc) = 0xf;
4065 MCHBAR16(0x11da) = 0x19;
4066 MCHBAR16(0x11ba) = 0x470c;
4067 MCHBAR32(0x1680) = 0xe6ffe4ff;
4068 MCHBAR32(0x1684) = 0xdeffdaff;
4069 MCHBAR32(0x1688) = 0xd4ffd0ff;
4070 MCHBAR32(0x168c) = 0xccffc6ff;
4071 MCHBAR32(0x1690) = 0xc0ffbeff;
4072 MCHBAR32(0x1694) = 0xb8ffb0ff;
4073 MCHBAR32(0x1698) = 0xa8ff0000;
4074 MCHBAR32(0x169c) = 0xc00;
4075 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004076 }
4077
Felix Held04be2dd2018-07-29 04:53:22 +02004078 MCHBAR32(0x124c) = 0x15040d00;
4079 MCHBAR32(0x1250) = 0x7f0000;
4080 MCHBAR32(0x1254) = 0x1e220004;
4081 MCHBAR32(0x1258) = 0x4000004;
4082 MCHBAR32(0x1278) = 0x0;
4083 MCHBAR32(0x125c) = 0x0;
4084 MCHBAR32(0x1260) = 0x0;
4085 MCHBAR32(0x1264) = 0x0;
4086 MCHBAR32(0x1268) = 0x0;
4087 MCHBAR32(0x126c) = 0x0;
4088 MCHBAR32(0x1270) = 0x0;
4089 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004090 }
4091
4092 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004093 MCHBAR16(0x1214) = 0x320;
4094 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004095 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4096 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004097 MCHBAR32(0x1400) = 0x13040020;
4098 MCHBAR32(0x1404) = 0xe090120;
4099 MCHBAR32(0x1408) = 0x5120220;
4100 MCHBAR32(0x140c) = 0x5120330;
4101 MCHBAR32(0x1410) = 0xe090220;
4102 MCHBAR32(0x1414) = 0x1010001;
4103 MCHBAR32(0x1418) = 0x1110000;
4104 MCHBAR32(0x141c) = 0x9020020;
4105 MCHBAR32(0x1420) = 0xd090220;
4106 MCHBAR32(0x1424) = 0x2090220;
4107 MCHBAR32(0x1428) = 0x2090330;
4108 MCHBAR32(0x142c) = 0xd090220;
4109 MCHBAR32(0x1430) = 0x1010001;
4110 MCHBAR32(0x1434) = 0x1110000;
4111 MCHBAR32(0x1438) = 0x11040020;
4112 MCHBAR32(0x143c) = 0x4030220;
4113 MCHBAR32(0x1440) = 0x1060220;
4114 MCHBAR32(0x1444) = 0x1060330;
4115 MCHBAR32(0x1448) = 0x4030220;
4116 MCHBAR32(0x144c) = 0x1010001;
4117 MCHBAR32(0x1450) = 0x1110000;
4118 MCHBAR32(0x1454) = 0x4010020;
4119 MCHBAR32(0x1458) = 0xb090220;
4120 MCHBAR32(0x145c) = 0x1090220;
4121 MCHBAR32(0x1460) = 0x1090330;
4122 MCHBAR32(0x1464) = 0xb090220;
4123 MCHBAR32(0x1468) = 0x1010001;
4124 MCHBAR32(0x146c) = 0x1110000;
4125 MCHBAR32(0x1470) = 0xf040020;
4126 MCHBAR32(0x1474) = 0xa090220;
4127 MCHBAR32(0x1478) = 0x1120220;
4128 MCHBAR32(0x147c) = 0x1120330;
4129 MCHBAR32(0x1480) = 0xa090220;
4130 MCHBAR32(0x1484) = 0x1010001;
4131 MCHBAR32(0x1488) = 0x1110000;
4132 MCHBAR32(0x148c) = 0x7020020;
4133 MCHBAR32(0x1490) = 0x1010220;
4134 MCHBAR32(0x1494) = 0x10210;
4135 MCHBAR32(0x1498) = 0x10320;
4136 MCHBAR32(0x149c) = 0x1010220;
4137 MCHBAR32(0x14a0) = 0x1010001;
4138 MCHBAR32(0x14a4) = 0x1110000;
4139 MCHBAR32(0x14a8) = 0xd040020;
4140 MCHBAR32(0x14ac) = 0x8090220;
4141 MCHBAR32(0x14b0) = 0x1111310;
4142 MCHBAR32(0x14b4) = 0x1111420;
4143 MCHBAR32(0x14b8) = 0x8090220;
4144 MCHBAR32(0x14bc) = 0x1010001;
4145 MCHBAR32(0x14c0) = 0x1110000;
4146 MCHBAR32(0x14c4) = 0x3010020;
4147 MCHBAR32(0x14c8) = 0x7090220;
4148 MCHBAR32(0x14cc) = 0x1081310;
4149 MCHBAR32(0x14d0) = 0x1081420;
4150 MCHBAR32(0x14d4) = 0x7090220;
4151 MCHBAR32(0x14d8) = 0x1010001;
4152 MCHBAR32(0x14dc) = 0x1110000;
4153 MCHBAR32(0x14e0) = 0xb040020;
4154 MCHBAR32(0x14e4) = 0x2030220;
4155 MCHBAR32(0x14e8) = 0x1051310;
4156 MCHBAR32(0x14ec) = 0x1051420;
4157 MCHBAR32(0x14f0) = 0x2030220;
4158 MCHBAR32(0x14f4) = 0x1010001;
4159 MCHBAR32(0x14f8) = 0x1110000;
4160 MCHBAR32(0x14fc) = 0x5020020;
4161 MCHBAR32(0x1500) = 0x5090220;
4162 MCHBAR32(0x1504) = 0x2071310;
4163 MCHBAR32(0x1508) = 0x2071420;
4164 MCHBAR32(0x150c) = 0x5090220;
4165 MCHBAR32(0x1510) = 0x1010001;
4166 MCHBAR32(0x1514) = 0x1110000;
4167 MCHBAR32(0x1518) = 0x7040120;
4168 MCHBAR32(0x151c) = 0x2090220;
4169 MCHBAR32(0x1520) = 0x70b1210;
4170 MCHBAR32(0x1524) = 0x70b1310;
4171 MCHBAR32(0x1528) = 0x2090220;
4172 MCHBAR32(0x152c) = 0x1010001;
4173 MCHBAR32(0x1530) = 0x1110000;
4174 MCHBAR32(0x1534) = 0x1010110;
4175 MCHBAR32(0x1538) = 0x1081310;
4176 MCHBAR32(0x153c) = 0x5041200;
4177 MCHBAR32(0x1540) = 0x5041310;
4178 MCHBAR32(0x1544) = 0x1081310;
4179 MCHBAR32(0x1548) = 0x1010001;
4180 MCHBAR32(0x154c) = 0x1110000;
4181 MCHBAR32(0x1550) = 0x1040120;
4182 MCHBAR32(0x1554) = 0x4051210;
4183 MCHBAR32(0x1558) = 0xd051200;
4184 MCHBAR32(0x155c) = 0xd051200;
4185 MCHBAR32(0x1560) = 0x4051210;
4186 MCHBAR32(0x1564) = 0x1010001;
4187 MCHBAR32(0x1568) = 0x1110000;
4188 MCHBAR16(0x1222) = 0x220a;
4189 MCHBAR16(0x123c) = 0x1fc0;
4190 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004191 }
4192
Felix Heldf83d80b2018-07-29 05:30:30 +02004193 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004194 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004195 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004196
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004197 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004198
4199 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004200 MCHBAR8_AND(0x2ca8, ~3);
4201 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004202 /* This issues a CPU reset without resetting the platform */
4203 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004204 /* Write back the S3 state to PM1_CNT to let the reset CPU
4205 know it also needs to take the s3 path. */
4206 if (s3resume)
4207 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4208 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004209 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004210 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004211 }
4212
Felix Held04be2dd2018-07-29 04:53:22 +02004213 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004214 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004215 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004216 MCHBAR16(0x2c20); // !!!!
4217 MCHBAR16(0x2c10); // !!!!
4218 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004219 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004220 udelay(1000);
4221 write_1d0(0, 0x33d, 0, 0);
4222 write_500(&info, 0, 0, 0xb61, 0, 0);
4223 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004224 MCHBAR32(0x1a30) = 0x0;
4225 MCHBAR32(0x1a34) = 0x0;
4226 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4227 (info.populated_ranks[0][0][0] * 0xa0);
4228 MCHBAR16(0x616) = 0x26a;
4229 MCHBAR32(0x134) = 0x856000;
4230 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004231 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4232 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004233 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004234 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4235 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004237 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004238 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4239 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004240 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4241 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4242 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4243 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4244 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4245 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4246 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4247 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4248 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4249 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004250 }
4251
4252 write_1d0(0x4, 0x151, 4, 1);
4253 write_1d0(0, 0x142, 3, 1);
4254 rdmsr(0x1ac); // !!!!
4255 write_500(&info, 1, 1, 0x6b3, 4, 1);
4256 write_500(&info, 1, 1, 0x6cf, 4, 1);
4257
4258 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4259
4260 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4261 populated_ranks[0]
4262 [0][0]) << 0),
4263 0x1d1, 3, 1);
4264 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004265 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4266 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004267 }
4268
4269 set_334(0);
4270
4271 program_base_timings(&info);
4272
Felix Held04be2dd2018-07-29 04:53:22 +02004273 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004274
4275 write_1d0(0x2, 0x1d5, 2, 1);
4276 write_1d0(0x20, 0x166, 7, 1);
4277 write_1d0(0x0, 0xeb, 3, 1);
4278 write_1d0(0x0, 0xf3, 6, 1);
4279
4280 for (channel = 0; channel < NUM_CHANNELS; channel++)
4281 for (lane = 0; lane < 9; lane++) {
4282 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4283 u8 a;
4284 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4285 write_500(&info, channel, a, addr, 6, 1);
4286 }
4287
4288 udelay(1000);
4289
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004290 if (s3resume) {
4291 if (info.cached_training == NULL) {
4292 u32 reg32;
4293 printk(BIOS_ERR,
4294 "Couldn't find training data. Rebooting\n");
4295 reg32 = inl(DEFAULT_PMBASE + 0x04);
4296 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004297 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004298 }
4299 int tm;
4300 info.training = *info.cached_training;
4301 for (tm = 0; tm < 4; tm++)
4302 for (channel = 0; channel < NUM_CHANNELS; channel++)
4303 for (slot = 0; slot < NUM_SLOTS; slot++)
4304 for (rank = 0; rank < NUM_RANKS; rank++)
4305 for (lane = 0; lane < 9; lane++)
4306 write_500(&info,
4307 channel,
4308 info.training.
4309 lane_timings
4310 [tm][channel]
4311 [slot][rank]
4312 [lane],
4313 get_timing_register_addr
4314 (lane, tm,
4315 slot, rank),
4316 9, 0);
4317 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4318 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4319 }
4320
Felix Heldf83d80b2018-07-29 05:30:30 +02004321 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004322 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004323 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004324 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004325
4326 program_board_delay(&info);
4327
Felix Held04be2dd2018-07-29 04:53:22 +02004328 MCHBAR8(0x5ff) = 0x0;
4329 MCHBAR8(0x5ff) = 0x80;
4330 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004331
Felix Held04be2dd2018-07-29 04:53:22 +02004332 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004333 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004334 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004335 gav(read_1d0(0x14b, 7)); // = 0x81023100
4336 write_1d0(0x30, 0x14b, 7, 1);
4337 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4338 write_1d0(7, 0xd6, 6, 1);
4339 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4340 write_1d0(7, 0x328, 6, 1);
4341
4342 for (channel = 0; channel < NUM_CHANNELS; channel++)
4343 set_4cf(&info, channel,
4344 info.populated_ranks[channel][0][0] ? 8 : 0);
4345
4346 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4347 write_1d0(2, 0x116, 4, 1);
4348 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4349 write_1d0(0, 0xae, 6, 1);
4350 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4351 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004352 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4353 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004354 MCHBAR32_AND(0x140, ~0x07000000);
4355 MCHBAR32_AND(0x138, ~0x07000000);
4356 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004357 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004358 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004359 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004360
4361 {
4362 u32 t;
4363 u8 val_a1;
4364 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4365 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4366 rmw_1d0(0x320, 0x07,
4367 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4368 rmw_1d0(0x14b, 0x78,
4369 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4370 4), 7,
4371 1);
4372 rmw_1d0(0xce, 0x38,
4373 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4374 4), 6,
4375 1);
4376 }
4377
4378 for (channel = 0; channel < NUM_CHANNELS; channel++)
4379 set_4cf(&info, channel,
4380 info.populated_ranks[channel][0][0] ? 9 : 1);
4381
4382 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004383 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004384 write_1d0(2, 0xae, 6, 1);
4385 write_1d0(2, 0x300, 6, 1);
4386 write_1d0(2, 0x121, 3, 1);
4387 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4388 write_1d0(4, 0xd6, 6, 1);
4389 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4390 write_1d0(4, 0x328, 6, 1);
4391
4392 for (channel = 0; channel < NUM_CHANNELS; channel++)
4393 set_4cf(&info, channel,
4394 info.populated_ranks[channel][0][0] ? 9 : 0);
4395
Felix Held04be2dd2018-07-29 04:53:22 +02004396 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4397 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004398 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004399 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004400 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4401 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4402 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4403 write_1d0(0, 0x21c, 6, 1);
4404 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4405 write_1d0(0x35, 0x14b, 7, 1);
4406
4407 for (channel = 0; channel < NUM_CHANNELS; channel++)
4408 set_4cf(&info, channel,
4409 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4410
4411 set_334(1);
4412
Felix Held04be2dd2018-07-29 04:53:22 +02004413 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004414
4415 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4416 write_500(&info, channel,
4417 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4418 1);
4419 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4420 }
Felix Held04be2dd2018-07-29 04:53:22 +02004421 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4422 MCHBAR16(0x6c0) = 0x14a0;
4423 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4424 MCHBAR16(0x232) = 0x8;
4425 /* 0x40004 or 0 depending on ? */
4426 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4427 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4428 MCHBAR32(0x128) = 0x2150d05;
4429 MCHBAR8(0x12c) = 0x1f;
4430 MCHBAR8(0x12d) = 0x56;
4431 MCHBAR8(0x12e) = 0x31;
4432 MCHBAR8(0x12f) = 0x0;
4433 MCHBAR8(0x271) = 0x2;
4434 MCHBAR8(0x671) = 0x2;
4435 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004436 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004437 MCHBAR32(0x294 + (channel << 10)) =
4438 (info.populated_ranks_mask[channel] & 3) << 16;
4439 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4440 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004441 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004442 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4443 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004444
4445 if (!s3resume)
4446 jedec_init(&info);
4447
4448 int totalrank = 0;
4449 for (channel = 0; channel < NUM_CHANNELS; channel++)
4450 for (slot = 0; slot < NUM_SLOTS; slot++)
4451 for (rank = 0; rank < NUM_RANKS; rank++)
4452 if (info.populated_ranks[channel][slot][rank]) {
4453 jedec_read(&info, channel, slot, rank,
4454 totalrank, 0xa, 0x400);
4455 totalrank++;
4456 }
4457
Felix Held04be2dd2018-07-29 04:53:22 +02004458 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004459
Felix Heldf83d80b2018-07-29 05:30:30 +02004460 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4461 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004462
4463 if (!s3resume) {
4464 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004465 MCHBAR32(0x294 + (channel << 10)) =
4466 (info.populated_ranks_mask[channel] & 3) << 16;
4467 MCHBAR16(0x298 + (channel << 10)) =
4468 info.populated_ranks[channel][0][0] |
4469 (info.populated_ranks[channel][0][1] << 5);
4470 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004471 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004472 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004473
4474 {
4475 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004476 a = MCHBAR8(0x243);
4477 b = MCHBAR8(0x643);
4478 MCHBAR8(0x243) = a | 2;
4479 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004480 }
4481
4482 write_1d0(7, 0x19b, 3, 1);
4483 write_1d0(7, 0x1c0, 3, 1);
4484 write_1d0(4, 0x1c6, 4, 1);
4485 write_1d0(4, 0x1cc, 4, 1);
4486 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4487 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004488 MCHBAR32(0x584) = 0xfffff;
4489 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004490
4491 for (channel = 0; channel < NUM_CHANNELS; channel++)
4492 for (slot = 0; slot < NUM_SLOTS; slot++)
4493 for (rank = 0; rank < NUM_RANKS; rank++)
4494 if (info.
4495 populated_ranks[channel][slot]
4496 [rank])
4497 config_rank(&info, s3resume,
4498 channel, slot,
4499 rank);
4500
Felix Held04be2dd2018-07-29 04:53:22 +02004501 MCHBAR8(0x243) = 0x1;
4502 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004503 }
4504
4505 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004506 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004507 write_26c(0, 0x820);
4508 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004509 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510 /* end */
4511
4512 if (s3resume) {
4513 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004514 MCHBAR32(0x294 + (channel << 10)) =
4515 (info.populated_ranks_mask[channel] & 3) << 16;
4516 MCHBAR16(0x298 + (channel << 10)) =
4517 info.populated_ranks[channel][0][0] |
4518 (info.populated_ranks[channel][0][1] << 5);
4519 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004521 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522 }
4523
Felix Held04be2dd2018-07-29 04:53:22 +02004524 MCHBAR32_AND(0xfa4, ~0x01000002);
4525 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004526
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004527 /* Before training. */
4528 timestamp_add_now(103);
4529
4530 if (!s3resume)
4531 ram_training(&info);
4532
4533 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004534 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535
4536 dump_timings(&info);
4537
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004538 program_modules_memory_map(&info, 0);
4539 program_total_memory_map(&info);
4540
4541 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004542 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004544 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004545 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004546 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547 else
Felix Held04be2dd2018-07-29 04:53:22 +02004548 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004549
Felix Held04be2dd2018-07-29 04:53:22 +02004550 MCHBAR32_AND(0xfac, ~0x80000000);
4551 MCHBAR32(0xfb4) = 0x4800;
4552 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4553 MCHBAR32(0xe94) = 0x7ffff;
4554 MCHBAR32(0xfc0) = 0x80002040;
4555 MCHBAR32(0xfc4) = 0x701246;
4556 MCHBAR8_AND(0xfc8, ~0x70);
4557 MCHBAR32_OR(0xe5c, 0x1000000);
4558 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4559 MCHBAR32(0x50) = 0x700b0;
4560 MCHBAR32(0x3c) = 0x10;
4561 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4562 MCHBAR8_OR(0xff4, 0x2);
4563 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004564
Felix Held04be2dd2018-07-29 04:53:22 +02004565 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4566 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4567 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004569 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4570 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4571 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573 {
4574 u32 eax;
4575
4576 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4578 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4579 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 }
4581
4582 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004585 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586 else
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004588
Felix Held04be2dd2018-07-29 04:53:22 +02004589 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004590
Felix Held04be2dd2018-07-29 04:53:22 +02004591 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004593 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594 else
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596 }
4597
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599
4600 {
4601 u8 al;
4602 al = 0xd;
4603 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4604 al += 2;
4605 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004606 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004607 }
4608
4609 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004610 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4611 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4612 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4613 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004614 }
4615 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004616 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004617 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004618 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004619 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004620 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004621 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004622 MCHBAR8_OR(0x1210, 2);
4623 MCHBAR32(0x1200) = 0x8800440;
4624 MCHBAR32(0x1204) = 0x53ff0453;
4625 MCHBAR32(0x1208) = 0x19002043;
4626 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627
4628 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR16(0x1214) = 0x220;
4630 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631 }
4632
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR8_OR(0x1214, 0x4);
4634 MCHBAR8(0x120c) = 0x1;
4635 MCHBAR8(0x1218) = 0x3;
4636 MCHBAR8(0x121a) = 0x3;
4637 MCHBAR8(0x121c) = 0x3;
4638 MCHBAR16(0xc14) = 0x0;
4639 MCHBAR16(0xc20) = 0x0;
4640 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641
4642 /* revision dependent here. */
4643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
4646 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648
Felix Held04be2dd2018-07-29 04:53:22 +02004649 MCHBAR16_OR(0x1230, 0x8000);
4650 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651
4652 u8 bl, ebpb;
4653 u16 reg_1020;
4654
Felix Held04be2dd2018-07-29 04:53:22 +02004655 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4656 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32(0x1000) = 0x100;
4659 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660
4661 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663 bl = reg_1020 >> 8;
4664 ebpb = reg_1020 & 0xff;
4665 } else {
4666 ebpb = 0;
4667 bl = 8;
4668 }
4669
4670 rdmsr(0x1a2);
4671
Felix Held04be2dd2018-07-29 04:53:22 +02004672 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675
Felix Held04be2dd2018-07-29 04:53:22 +02004676 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677
Felix Held04be2dd2018-07-29 04:53:22 +02004678 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004679 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004680 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4681 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682 }
4683
4684 setup_heci_uma(&info);
4685
4686 if (info.uma_enabled) {
4687 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004688 MCHBAR32_OR(0x11b0, 0x4000);
4689 MCHBAR32_OR(0x11b4, 0x4000);
4690 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
Felix Held04be2dd2018-07-29 04:53:22 +02004692 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4693 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4694 MCHBAR16_OR(0x1170, 0x1000);
4695
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004696 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004697
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004699 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004700 ;
4701 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004702 }
4703
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004704 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4705 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004707 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004708
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 udelay(1000);
4710 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004711 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4712
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713 if (!s3resume)
4714 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004715 if (s3resume && cbmem_wasnot_inited) {
4716 u32 reg32;
4717 printk(BIOS_ERR, "Failed S3 resume.\n");
4718 ram_check(0x100000, 0x200000);
4719
4720 /* Clear SLP_TYPE. */
4721 reg32 = inl(DEFAULT_PMBASE + 0x04);
4722 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4723
4724 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004725 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004726 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727}