blob: 68eefec9dddbe12a591b82d0502df995853f8d71 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Angel Pons36592bf2020-09-14 18:52:44 +020064#define MRC_CACHE_VERSION 3
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100104/* OK */
105static void write_1d0(u32 val, u16 addr, int bits, int flag)
106{
Felix Held04be2dd2018-07-29 04:53:22 +0200107 MCHBAR32(0x1d0) = 0;
108 while (MCHBAR32(0x1d0) & 0x800000)
109 ;
110 MCHBAR32(0x1d4) =
111 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
112 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200113 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200114 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100115}
116
117/* OK */
118static u16 read_1d0(u16 addr, int split)
119{
120 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200121 MCHBAR32(0x1d0) = 0;
122 while (MCHBAR32(0x1d0) & 0x800000)
123 ;
124 MCHBAR32(0x1d0) =
125 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
126 while (MCHBAR32(0x1d0) & 0x800000)
127 ;
128 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100129 write_1d0(0, 0x33d, 0, 0);
130 write_1d0(0, 0x33d, 0, 0);
131 val &= ((1 << split) - 1);
132 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
133 return val;
134}
135
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800136static void write32p(uintptr_t addr, uint32_t val)
137{
138 write32((void *)addr, val);
139}
140
141static uint32_t read32p(uintptr_t addr)
142{
143 return read32((void *)addr);
144}
145
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146static void sfence(void)
147{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100148 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100149}
150
151static inline u16 get_lane_offset(int slot, int rank, int lane)
152{
153 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
154 0x452 * (lane == 8);
155}
156
157static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
158{
159 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
160 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static u32 gav_real(int line, u32 in)
164{
165 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
166 return in;
167}
168
169#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200170
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100171struct raminfo {
172 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
173 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
174 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
175 u8 density[2][2]; /* [CHANNEL][SLOT] */
176 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
177 int rank_start[2][2][2];
178 u8 cas_latency;
179 u8 board_lane_delay[9];
180 u8 use_ecc;
181 u8 revision;
182 u8 max_supported_clock_speed_index;
183 u8 uma_enabled;
184 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
185 u8 silicon_revision;
186 u8 populated_ranks_mask[2];
187 u8 max_slots_used_in_channel;
188 u8 mode4030[2];
189 u16 avg4044[2];
190 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600191 unsigned int total_memory_mb;
192 unsigned int interleaved_part_mb;
193 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100194
Martin Roth468d02c2019-10-23 21:44:42 -0600195 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196
197 struct ram_training training;
198 u32 last_500_command[2];
199
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100200 u32 delay46_ps[2];
201 u32 delay54_ps[2];
202 u8 revision_flag_1;
203 u8 some_delay_1_cycle_floor;
204 u8 some_delay_2_halfcycles_ceil;
205 u8 some_delay_3_ps_rounded;
206
207 const struct ram_training *cached_training;
208};
209
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200210/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100211timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200212
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100213static void
214write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
215 int flag);
216
217/* OK */
218static u16
219read_500(struct raminfo *info, int channel, u16 addr, int split)
220{
221 u32 val;
222 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200223 MCHBAR32(0x500 + (channel << 10)) = 0;
224 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
225 ;
226 MCHBAR32(0x500 + (channel << 10)) =
227 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
228 + 0xb88 - addr);
229 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
230 ;
231 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232 return val & ((1 << split) - 1);
233}
234
235/* OK */
236static void
237write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
238 int flag)
239{
240 if (info->last_500_command[channel] == 0x80000000) {
241 info->last_500_command[channel] = 0x40000000;
242 write_500(info, channel, 0, 0xb61, 0, 0);
243 }
Felix Held04be2dd2018-07-29 04:53:22 +0200244 MCHBAR32(0x500 + (channel << 10)) = 0;
245 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
246 ;
247 MCHBAR32(0x504 + (channel << 10)) =
248 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
249 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200250 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200251 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100252}
253
254static int rw_test(int rank)
255{
256 const u32 mask = 0xf00fc33c;
257 int ok = 0xff;
258 int i;
259 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800260 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261 sfence();
262 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800263 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100264 sfence();
265 for (i = 0; i < 32; i++) {
266 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800267 write32p((rank << 28) | (i << 3), pat);
268 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100269 }
270 sfence();
271 for (i = 0; i < 32; i++) {
272 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
273 int j;
274 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800275 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276 for (j = 0; j < 4; j++)
277 if (((val >> (j * 8)) & 0xff) != pat)
278 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 for (j = 0; j < 4; j++)
281 if (((val >> (j * 8)) & 0xff) != pat)
282 ok &= ~(16 << j);
283 }
284 sfence();
285 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800286 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100287 sfence();
288 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800289 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100290
291 return ok;
292}
293
294static void
295program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
296{
297 int lane;
298 for (lane = 0; lane < 8; lane++) {
299 write_500(info, channel,
300 base +
301 info->training.
302 lane_timings[2][channel][slot][rank][lane],
303 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
304 write_500(info, channel,
305 base +
306 info->training.
307 lane_timings[3][channel][slot][rank][lane],
308 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
309 }
310}
311
312static void write_26c(int channel, u16 si)
313{
Felix Held04be2dd2018-07-29 04:53:22 +0200314 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
315 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
316 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100317}
318
319static u32 get_580(int channel, u8 addr)
320{
321 u32 ret;
322 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200323 MCHBAR8(0x5ff) = 0x0;
324 MCHBAR8(0x5ff) = 0x80;
325 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
326 MCHBAR8_OR(0x580 + (channel << 10), 1);
327 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
328 ;
329 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100330 return ret;
331}
332
333const int cached_config = 0;
334
335#define NUM_CHANNELS 2
336#define NUM_SLOTS 2
337#define NUM_RANKS 2
338#define RANK_SHIFT 28
339#define CHANNEL_SHIFT 10
340
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100341static void seq9(struct raminfo *info, int channel, int slot, int rank)
342{
343 int i, lane;
344
345 for (i = 0; i < 2; i++)
346 for (lane = 0; lane < 8; lane++)
347 write_500(info, channel,
348 info->training.lane_timings[i +
349 1][channel][slot]
350 [rank][lane], get_timing_register_addr(lane,
351 i + 1,
352 slot,
353 rank),
354 9, 0);
355
356 write_1d0(1, 0x103, 6, 1);
357 for (lane = 0; lane < 8; lane++)
358 write_500(info, channel,
359 info->training.
360 lane_timings[0][channel][slot][rank][lane],
361 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
362
363 for (i = 0; i < 2; i++) {
364 for (lane = 0; lane < 8; lane++)
365 write_500(info, channel,
366 info->training.lane_timings[i +
367 1][channel][slot]
368 [rank][lane], get_timing_register_addr(lane,
369 i + 1,
370 slot,
371 rank),
372 9, 0);
373 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
374 }
375
376 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200377 MCHBAR8(0x5ff) = 0x0;
378 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100379 write_1d0(0x2, 0x142, 3, 1);
380 for (lane = 0; lane < 8; lane++) {
381 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
382 info->training.lane_timings[2][channel][slot][rank][lane] =
383 read_500(info, channel,
384 get_timing_register_addr(lane, 2, slot, rank), 9);
385 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
386 info->training.lane_timings[3][channel][slot][rank][lane] =
387 info->training.lane_timings[2][channel][slot][rank][lane] +
388 0x20;
389 }
390}
391
392static int count_ranks_in_channel(struct raminfo *info, int channel)
393{
394 int slot, rank;
395 int res = 0;
396 for (slot = 0; slot < NUM_SLOTS; slot++)
397 for (rank = 0; rank < NUM_SLOTS; rank++)
398 res += info->populated_ranks[channel][slot][rank];
399 return res;
400}
401
402static void
403config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
404{
405 int add;
406
407 write_1d0(0, 0x178, 7, 1);
408 seq9(info, channel, slot, rank);
409 program_timings(info, 0x80, channel, slot, rank);
410
411 if (channel == 0)
412 add = count_ranks_in_channel(info, 1);
413 else
414 add = 0;
415 if (!s3resume)
416 gav(rw_test(rank + add));
417 program_timings(info, 0x00, channel, slot, rank);
418 if (!s3resume)
419 gav(rw_test(rank + add));
420 if (!s3resume)
421 gav(rw_test(rank + add));
422 write_1d0(0, 0x142, 3, 1);
423 write_1d0(0, 0x103, 6, 1);
424
425 gav(get_580(channel, 0xc | (rank << 5)));
426 gav(read_1d0(0x142, 3));
427
Felix Held04be2dd2018-07-29 04:53:22 +0200428 MCHBAR8(0x5ff) = 0x0;
429 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100430}
431
432static void set_4cf(struct raminfo *info, int channel, u8 val)
433{
434 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
435 write_500(info, channel, val, 0x4cf, 4, 1);
436 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
437 write_500(info, channel, val, 0x659, 4, 1);
438 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
439 write_500(info, channel, val, 0x697, 4, 1);
440}
441
442static void set_334(int zero)
443{
444 int j, k, channel;
445 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
446 u32 vd8[2][16];
447
448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
449 for (j = 0; j < 4; j++) {
450 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
451 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
452 u16 c;
453 if ((j == 0 || j == 3) && zero)
454 c = 0;
455 else if (j == 3)
456 c = 0x5f;
457 else
458 c = 0x5f5f;
459
460 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200461 MCHBAR32(0x138 + 8 * k) =
462 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100463 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200464 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100465 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200466 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100467 }
468
Felix Held22ca8cb2018-07-29 05:09:44 +0200469 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
470 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200471 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
472 zero ? 0 : (0x18191819 & lmask);
473 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
474 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
475 zero ? 0 : (a & lmask);
476 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100478 }
479 }
480
Felix Held04be2dd2018-07-29 04:53:22 +0200481 MCHBAR32_OR(0x130, 1);
482 while (MCHBAR8(0x130) & 1)
483 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484}
485
486static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
487{
488 u32 v;
489 v = read_1d0(addr, split);
490 write_1d0((v & and) | or, addr, split, flag);
491}
492
493static int find_highest_bit_set(u16 val)
494{
495 int i;
496 for (i = 15; i >= 0; i--)
497 if (val & (1 << i))
498 return i;
499 return -1;
500}
501
502static int find_lowest_bit_set32(u32 val)
503{
504 int i;
505 for (i = 0; i < 32; i++)
506 if (val & (1 << i))
507 return i;
508 return -1;
509}
510
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100511enum {
512 DEVICE_TYPE = 2,
513 MODULE_TYPE = 3,
514 DENSITY = 4,
515 RANKS_AND_DQ = 7,
516 MEMORY_BUS_WIDTH = 8,
517 TIMEBASE_DIVIDEND = 10,
518 TIMEBASE_DIVISOR = 11,
519 CYCLETIME = 12,
520
521 CAS_LATENCIES_LSB = 14,
522 CAS_LATENCIES_MSB = 15,
523 CAS_LATENCY_TIME = 16,
524 THERMAL_AND_REFRESH = 31,
525 REFERENCE_RAW_CARD_USED = 62,
526 RANK1_ADDRESS_MAPPING = 63
527};
528
529static void calculate_timings(struct raminfo *info)
530{
Martin Roth468d02c2019-10-23 21:44:42 -0600531 unsigned int cycletime;
532 unsigned int cas_latency_time;
533 unsigned int supported_cas_latencies;
534 unsigned int channel, slot;
535 unsigned int clock_speed_index;
536 unsigned int min_cas_latency;
537 unsigned int cas_latency;
538 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100539
540 /* Find common CAS latency */
541 supported_cas_latencies = 0x3fe;
542 for (channel = 0; channel < NUM_CHANNELS; channel++)
543 for (slot = 0; slot < NUM_SLOTS; slot++)
544 if (info->populated_ranks[channel][slot][0])
545 supported_cas_latencies &=
546 2 *
547 (info->
548 spd[channel][slot][CAS_LATENCIES_LSB] |
549 (info->
550 spd[channel][slot][CAS_LATENCIES_MSB] <<
551 8));
552
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100553 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100554
555 cycletime = min_cycletime[max_clock_index];
556 cas_latency_time = min_cas_latency_time[max_clock_index];
557
558 for (channel = 0; channel < NUM_CHANNELS; channel++)
559 for (slot = 0; slot < NUM_SLOTS; slot++)
560 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600561 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100562 timebase =
563 1000 *
564 info->
565 spd[channel][slot][TIMEBASE_DIVIDEND] /
566 info->spd[channel][slot][TIMEBASE_DIVISOR];
567 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100568 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100569 timebase *
570 info->spd[channel][slot][CYCLETIME]);
571 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100572 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100573 timebase *
574 info->
575 spd[channel][slot][CAS_LATENCY_TIME]);
576 }
Jacob Garber3c193822019-06-10 18:23:32 -0600577 if (cycletime > min_cycletime[0])
578 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100579 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
580 if (cycletime == min_cycletime[clock_speed_index])
581 break;
582 if (cycletime > min_cycletime[clock_speed_index]) {
583 clock_speed_index--;
584 cycletime = min_cycletime[clock_speed_index];
585 break;
586 }
587 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100588 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100589 cas_latency = 0;
590 while (supported_cas_latencies) {
591 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
592 if (cas_latency <= min_cas_latency)
593 break;
594 supported_cas_latencies &=
595 ~(1 << find_highest_bit_set(supported_cas_latencies));
596 }
597
598 if (cas_latency != min_cas_latency && clock_speed_index)
599 clock_speed_index--;
600
601 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
602 die("Couldn't configure DRAM");
603 info->clock_speed_index = clock_speed_index;
604 info->cas_latency = cas_latency;
605}
606
607static void program_base_timings(struct raminfo *info)
608{
Martin Roth468d02c2019-10-23 21:44:42 -0600609 unsigned int channel;
610 unsigned int slot, rank, lane;
611 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100612 int i;
613
614 extended_silicon_revision = info->silicon_revision;
615 if (info->silicon_revision == 0)
616 for (channel = 0; channel < NUM_CHANNELS; channel++)
617 for (slot = 0; slot < NUM_SLOTS; slot++)
618 if ((info->
619 spd[channel][slot][MODULE_TYPE] & 0xF) ==
620 3)
621 extended_silicon_revision = 4;
622
623 for (channel = 0; channel < NUM_CHANNELS; channel++) {
624 for (slot = 0; slot < NUM_SLOTS; slot++)
625 for (rank = 0; rank < NUM_SLOTS; rank++) {
626 int card_timing_2;
627 if (!info->populated_ranks[channel][slot][rank])
628 continue;
629
630 for (lane = 0; lane < 9; lane++) {
631 int tm_reg;
632 int card_timing;
633
634 card_timing = 0;
635 if ((info->
636 spd[channel][slot][MODULE_TYPE] &
637 0xF) == 3) {
638 int reference_card;
639 reference_card =
640 info->
641 spd[channel][slot]
642 [REFERENCE_RAW_CARD_USED] &
643 0x1f;
644 if (reference_card == 3)
645 card_timing =
646 u16_ffd1188[0][lane]
647 [info->
648 clock_speed_index];
649 if (reference_card == 5)
650 card_timing =
651 u16_ffd1188[1][lane]
652 [info->
653 clock_speed_index];
654 }
655
656 info->training.
657 lane_timings[0][channel][slot][rank]
658 [lane] =
659 u8_FFFD1218[info->
660 clock_speed_index];
661 info->training.
662 lane_timings[1][channel][slot][rank]
663 [lane] = 256;
664
665 for (tm_reg = 2; tm_reg < 4; tm_reg++)
666 info->training.
667 lane_timings[tm_reg]
668 [channel][slot][rank][lane]
669 =
670 u8_FFFD1240[channel]
671 [extended_silicon_revision]
672 [lane][2 * slot +
673 rank][info->
674 clock_speed_index]
675 + info->max4048[channel]
676 +
677 u8_FFFD0C78[channel]
678 [extended_silicon_revision]
679 [info->
680 mode4030[channel]][slot]
681 [rank][info->
682 clock_speed_index]
683 + card_timing;
684 for (tm_reg = 0; tm_reg < 4; tm_reg++)
685 write_500(info, channel,
686 info->training.
687 lane_timings[tm_reg]
688 [channel][slot][rank]
689 [lane],
690 get_timing_register_addr
691 (lane, tm_reg, slot,
692 rank), 9, 0);
693 }
694
695 card_timing_2 = 0;
696 if (!(extended_silicon_revision != 4
697 || (info->
698 populated_ranks_mask[channel] & 5) ==
699 5)) {
700 if ((info->
701 spd[channel][slot]
702 [REFERENCE_RAW_CARD_USED] & 0x1F)
703 == 3)
704 card_timing_2 =
705 u16_FFFE0EB8[0][info->
706 clock_speed_index];
707 if ((info->
708 spd[channel][slot]
709 [REFERENCE_RAW_CARD_USED] & 0x1F)
710 == 5)
711 card_timing_2 =
712 u16_FFFE0EB8[1][info->
713 clock_speed_index];
714 }
715
716 for (i = 0; i < 3; i++)
717 write_500(info, channel,
718 (card_timing_2 +
719 info->max4048[channel]
720 +
721 u8_FFFD0EF8[channel]
722 [extended_silicon_revision]
723 [info->
724 mode4030[channel]][info->
725 clock_speed_index]),
726 u16_fffd0c50[i][slot][rank],
727 8, 1);
728 write_500(info, channel,
729 (info->max4048[channel] +
730 u8_FFFD0C78[channel]
731 [extended_silicon_revision][info->
732 mode4030
733 [channel]]
734 [slot][rank][info->
735 clock_speed_index]),
736 u16_fffd0c70[slot][rank], 7, 1);
737 }
738 if (!info->populated_ranks_mask[channel])
739 continue;
740 for (i = 0; i < 3; i++)
741 write_500(info, channel,
742 (info->max4048[channel] +
743 info->avg4044[channel]
744 +
745 u8_FFFD17E0[channel]
746 [extended_silicon_revision][info->
747 mode4030
748 [channel]][info->
749 clock_speed_index]),
750 u16_fffd0c68[i], 8, 1);
751 }
752}
753
754static unsigned int fsbcycle_ps(struct raminfo *info)
755{
756 return 900000 / info->fsb_frequency;
757}
758
759/* The time of DDR transfer in ps. */
760static unsigned int halfcycle_ps(struct raminfo *info)
761{
762 return 3750 / (info->clock_speed_index + 3);
763}
764
765/* The time of clock cycle in ps. */
766static unsigned int cycle_ps(struct raminfo *info)
767{
768 return 2 * halfcycle_ps(info);
769}
770
771/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600772static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100773{
774 return (info->clock_speed_index + 3) * 120;
775}
776
777/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600778static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100779{
780 return 100 * frequency_11(info) / 9;
781}
782
Martin Roth468d02c2019-10-23 21:44:42 -0600783static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100784{
785 return (frequency_11(info) * 2) * ps / 900000;
786}
787
Martin Roth468d02c2019-10-23 21:44:42 -0600788static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100789{
790 return (frequency_11(info)) * ns / 900;
791}
792
793static void compute_derived_timings(struct raminfo *info)
794{
Martin Roth468d02c2019-10-23 21:44:42 -0600795 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100796 int extended_silicon_revision;
797 int some_delay_1_ps;
798 int some_delay_2_ps;
799 int some_delay_2_halfcycles_ceil;
800 int some_delay_2_halfcycles_floor;
801 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100802 int some_delay_3_ps_rounded;
803 int some_delay_1_cycle_ceil;
804 int some_delay_1_cycle_floor;
805
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100806 some_delay_3_ps_rounded = 0;
807 extended_silicon_revision = info->silicon_revision;
808 if (!info->silicon_revision)
809 for (channel = 0; channel < NUM_CHANNELS; channel++)
810 for (slot = 0; slot < NUM_SLOTS; slot++)
811 if ((info->
812 spd[channel][slot][MODULE_TYPE] & 0xF) ==
813 3)
814 extended_silicon_revision = 4;
815 if (info->board_lane_delay[7] < 5)
816 info->board_lane_delay[7] = 5;
817 info->revision_flag_1 = 2;
818 if (info->silicon_revision == 2 || info->silicon_revision == 3)
819 info->revision_flag_1 = 0;
820 if (info->revision < 16)
821 info->revision_flag_1 = 0;
822
823 if (info->revision < 8)
824 info->revision_flag_1 = 0;
825 if (info->revision >= 8 && (info->silicon_revision == 0
826 || info->silicon_revision == 1))
827 some_delay_2_ps = 735;
828 else
829 some_delay_2_ps = 750;
830
831 if (info->revision >= 0x10 && (info->silicon_revision == 0
832 || info->silicon_revision == 1))
833 some_delay_1_ps = 3929;
834 else
835 some_delay_1_ps = 3490;
836
837 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
838 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
839 if (some_delay_1_ps % cycle_ps(info))
840 some_delay_1_cycle_ceil++;
841 else
842 some_delay_1_cycle_floor--;
843 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
844 if (info->revision_flag_1)
845 some_delay_2_ps = halfcycle_ps(info) >> 6;
846 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100847 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100848 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
849 375;
850 some_delay_3_ps =
851 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
852 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200853 if (some_delay_3_ps >= 150) {
854 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100855 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200856 some_delay_3_ps_rounded =
857 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
858 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100859 }
860 some_delay_2_halfcycles_ceil =
861 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
862 2 * (some_delay_1_cycle_ceil - 1);
863 if (info->revision_flag_1 && some_delay_3_ps < 150)
864 some_delay_2_halfcycles_ceil++;
865 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
866 if (info->revision < 0x10)
867 some_delay_2_halfcycles_floor =
868 some_delay_2_halfcycles_ceil - 1;
869 if (!info->revision_flag_1)
870 some_delay_2_halfcycles_floor++;
871 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
872 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
873 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
874 || (info->populated_ranks[1][0][0]
875 && info->populated_ranks[1][1][0]))
876 info->max_slots_used_in_channel = 2;
877 else
878 info->max_slots_used_in_channel = 1;
879 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200880 MCHBAR32(0x244 + (channel << 10)) =
881 ((info->revision < 8) ? 1 : 0x200) |
882 ((2 - info->max_slots_used_in_channel) << 17) |
883 (channel << 21) |
884 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100885 if (info->max_slots_used_in_channel == 1) {
886 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
887 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
888 } else {
889 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
890 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
891 || (count_ranks_in_channel(info, 1) ==
892 2)) ? 2 : 3;
893 }
894 for (channel = 0; channel < NUM_CHANNELS; channel++) {
895 int max_of_unk;
896 int min_of_unk_2;
897
898 int i, count;
899 int sum;
900
901 if (!info->populated_ranks_mask[channel])
902 continue;
903
904 max_of_unk = 0;
905 min_of_unk_2 = 32767;
906
907 sum = 0;
908 count = 0;
909 for (i = 0; i < 3; i++) {
910 int unk1;
911 if (info->revision < 8)
912 unk1 =
913 u8_FFFD1891[0][channel][info->
914 clock_speed_index]
915 [i];
916 else if (!
917 (info->revision >= 0x10
918 || info->revision_flag_1))
919 unk1 =
920 u8_FFFD1891[1][channel][info->
921 clock_speed_index]
922 [i];
923 else
924 unk1 = 0;
925 for (slot = 0; slot < NUM_SLOTS; slot++)
926 for (rank = 0; rank < NUM_RANKS; rank++) {
927 int a = 0;
928 int b = 0;
929
930 if (!info->
931 populated_ranks[channel][slot]
932 [rank])
933 continue;
934 if (extended_silicon_revision == 4
935 && (info->
936 populated_ranks_mask[channel] &
937 5) != 5) {
938 if ((info->
939 spd[channel][slot]
940 [REFERENCE_RAW_CARD_USED] &
941 0x1F) == 3) {
942 a = u16_ffd1178[0]
943 [info->
944 clock_speed_index];
945 b = u16_fe0eb8[0][info->
946 clock_speed_index];
947 } else
948 if ((info->
949 spd[channel][slot]
950 [REFERENCE_RAW_CARD_USED]
951 & 0x1F) == 5) {
952 a = u16_ffd1178[1]
953 [info->
954 clock_speed_index];
955 b = u16_fe0eb8[1][info->
956 clock_speed_index];
957 }
958 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100959 min_of_unk_2 = MIN(min_of_unk_2, a);
960 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100961 if (rank == 0) {
962 sum += a;
963 count++;
964 }
965 {
966 int t;
967 t = b +
968 u8_FFFD0EF8[channel]
969 [extended_silicon_revision]
970 [info->
971 mode4030[channel]][info->
972 clock_speed_index];
973 if (unk1 >= t)
974 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100975 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100976 unk1 - t);
977 }
978 }
979 {
980 int t =
981 u8_FFFD17E0[channel]
982 [extended_silicon_revision][info->
983 mode4030
984 [channel]]
985 [info->clock_speed_index] + min_of_unk_2;
986 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100987 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100988 }
989 }
990
Jacob Garber64fb4a32019-06-10 17:29:18 -0600991 if (count == 0)
992 die("No memory ranks found for channel %u\n", channel);
993
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100994 info->avg4044[channel] = sum / count;
995 info->max4048[channel] = max_of_unk;
996 }
997}
998
999static void jedec_read(struct raminfo *info,
1000 int channel, int slot, int rank,
1001 int total_rank, u8 addr3, unsigned int value)
1002{
1003 /* Handle mirrored mapping. */
1004 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001005 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1006 ((addr3 >> 1) & 0x10);
1007 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1008 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001009
1010 /* Handle mirrored mapping. */
1011 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1012 value =
1013 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1014 << 1);
1015
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001016 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001017
Felix Held04be2dd2018-07-29 04:53:22 +02001018 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1019 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001020
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001021 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022}
1023
1024enum {
1025 MR1_RZQ12 = 512,
1026 MR1_RZQ2 = 64,
1027 MR1_RZQ4 = 4,
1028 MR1_ODS34OHM = 2
1029};
1030
1031enum {
1032 MR0_BT_INTERLEAVED = 8,
1033 MR0_DLL_RESET_ON = 256
1034};
1035
1036enum {
1037 MR2_RTT_WR_DISABLED = 0,
1038 MR2_RZQ2 = 1 << 10
1039};
1040
1041static void jedec_init(struct raminfo *info)
1042{
1043 int write_recovery;
1044 int channel, slot, rank;
1045 int total_rank;
1046 int dll_on;
1047 int self_refresh_temperature;
1048 int auto_self_refresh;
1049
1050 auto_self_refresh = 1;
1051 self_refresh_temperature = 1;
1052 if (info->board_lane_delay[3] <= 10) {
1053 if (info->board_lane_delay[3] <= 8)
1054 write_recovery = info->board_lane_delay[3] - 4;
1055 else
1056 write_recovery = 5;
1057 } else {
1058 write_recovery = 6;
1059 }
1060 FOR_POPULATED_RANKS {
1061 auto_self_refresh &=
1062 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1063 self_refresh_temperature &=
1064 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1065 }
1066 if (auto_self_refresh == 1)
1067 self_refresh_temperature = 0;
1068
1069 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1070 || (info->populated_ranks[0][0][0]
1071 && info->populated_ranks[0][1][0])
1072 || (info->populated_ranks[1][0][0]
1073 && info->populated_ranks[1][1][0]));
1074
1075 total_rank = 0;
1076
1077 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1078 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1079 int rzq_reg58e;
1080
1081 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1082 rzq_reg58e = 64;
1083 rtt = MR1_RZQ2;
1084 if (info->clock_speed_index != 0) {
1085 rzq_reg58e = 4;
1086 if (info->populated_ranks_mask[channel] == 3)
1087 rtt = MR1_RZQ4;
1088 }
1089 } else {
1090 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1091 rtt = MR1_RZQ12;
1092 rzq_reg58e = 64;
1093 rtt_wr = MR2_RZQ2;
1094 } else {
1095 rzq_reg58e = 4;
1096 rtt = MR1_RZQ4;
1097 }
1098 }
1099
Felix Held04be2dd2018-07-29 04:53:22 +02001100 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1101 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1102 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1103 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1104 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001105
1106 for (slot = 0; slot < NUM_SLOTS; slot++)
1107 for (rank = 0; rank < NUM_RANKS; rank++)
1108 if (info->populated_ranks[channel][slot][rank]) {
1109 jedec_read(info, channel, slot, rank,
1110 total_rank, 0x28,
1111 rtt_wr | (info->
1112 clock_speed_index
1113 << 3)
1114 | (auto_self_refresh << 6) |
1115 (self_refresh_temperature <<
1116 7));
1117 jedec_read(info, channel, slot, rank,
1118 total_rank, 0x38, 0);
1119 jedec_read(info, channel, slot, rank,
1120 total_rank, 0x18,
1121 rtt | MR1_ODS34OHM);
1122 jedec_read(info, channel, slot, rank,
1123 total_rank, 6,
1124 (dll_on << 12) |
1125 (write_recovery << 9)
1126 | ((info->cas_latency - 4) <<
1127 4) | MR0_BT_INTERLEAVED |
1128 MR0_DLL_RESET_ON);
1129 total_rank++;
1130 }
1131 }
1132}
1133
1134static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1135{
Martin Roth468d02c2019-10-23 21:44:42 -06001136 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001137 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1138 unsigned int channel_0_non_interleaved;
1139
1140 FOR_ALL_RANKS {
1141 if (info->populated_ranks[channel][slot][rank]) {
1142 total_mb[channel] +=
1143 pre_jedec ? 256 : (256 << info->
1144 density[channel][slot] >> info->
1145 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001146 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1147 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1148 (info->is_x16_module[channel][slot] |
1149 ((info->density[channel][slot] + 1) << 1))) |
1150 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001151 }
Felix Held04be2dd2018-07-29 04:53:22 +02001152 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1153 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001154 }
1155
1156 info->total_memory_mb = total_mb[0] + total_mb[1];
1157
1158 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001159 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001160 info->non_interleaved_part_mb =
1161 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1162 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001163 MCHBAR32(0x100) = channel_0_non_interleaved |
1164 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001165 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001166 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167}
1168
1169static void program_board_delay(struct raminfo *info)
1170{
1171 int cas_latency_shift;
1172 int some_delay_ns;
1173 int some_delay_3_half_cycles;
1174
Martin Roth468d02c2019-10-23 21:44:42 -06001175 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001176 int high_multiplier;
1177 int lane_3_delay;
1178 int cas_latency_derived;
1179
1180 high_multiplier = 0;
1181 some_delay_ns = 200;
1182 some_delay_3_half_cycles = 4;
1183 cas_latency_shift = info->silicon_revision == 0
1184 || info->silicon_revision == 1 ? 1 : 0;
1185 if (info->revision < 8) {
1186 some_delay_ns = 600;
1187 cas_latency_shift = 0;
1188 }
1189 {
1190 int speed_bit;
1191 speed_bit =
1192 ((info->clock_speed_index > 1
1193 || (info->silicon_revision != 2
1194 && info->silicon_revision != 3))) ^ (info->revision >=
1195 0x10);
1196 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1197 3, 1);
1198 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1199 3, 1);
1200 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1201 && (info->silicon_revision == 2
1202 || info->silicon_revision == 3))
1203 rmw_1d0(0x116, 5, 2, 4, 1);
1204 }
Felix Held04be2dd2018-07-29 04:53:22 +02001205 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1206 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001207
Felix Held04be2dd2018-07-29 04:53:22 +02001208 MCHBAR8(0x124) = info->board_lane_delay[4] +
1209 ((frequency_01(info) + 999) / 1000);
1210 MCHBAR16(0x125) = 0x1360;
1211 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001213 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214 high_multiplier = 1;
1215 some_delay_2_half_cycles = ps_to_halfcycles(info,
1216 ((3 *
1217 fsbcycle_ps(info))
1218 >> 1) +
1219 (halfcycle_ps(info)
1220 *
1221 reg178_min[info->
1222 clock_speed_index]
1223 >> 6)
1224 +
1225 4 *
1226 halfcycle_ps(info)
1227 + 2230);
1228 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001229 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230 (frequency_11(info) * 2) * (28 -
1231 some_delay_2_half_cycles) /
1232 (frequency_11(info) * 2 -
1233 4 * (info->fsb_frequency))) >> 3, 7);
1234 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001235 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001236 some_delay_3_half_cycles = 3;
1237 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001238 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1239 MCHBAR32(0x224 + (channel << 10)) =
1240 (info->max_slots_used_in_channel - 1) |
1241 ((info->cas_latency - 5 - info->clock_speed_index)
1242 << 21) | ((info->max_slots_used_in_channel +
1243 info->cas_latency - cas_latency_shift - 4) << 16) |
1244 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1245 ((info->cas_latency - info->clock_speed_index +
1246 info->max_slots_used_in_channel - 6) << 8);
1247 MCHBAR32(0x228 + (channel << 10)) =
1248 info->max_slots_used_in_channel;
1249 MCHBAR8(0x239 + (channel << 10)) = 32;
1250 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1251 (some_delay_3_half_cycles << 25) | 0x840000;
1252 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1253 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1254 MCHBAR32(0x24c + (channel << 10)) =
1255 ((!!info->clock_speed_index) << 17) |
1256 (((2 + info->clock_speed_index -
1257 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258
Felix Held04be2dd2018-07-29 04:53:22 +02001259 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1260 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1261 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001262
1263 write_500(info, channel,
1264 ((!info->populated_ranks[channel][1][1])
1265 | (!info->populated_ranks[channel][1][0] << 1)
1266 | (!info->populated_ranks[channel][0][1] << 2)
1267 | (!info->populated_ranks[channel][0][0] << 3)),
1268 0x4c9, 4, 1);
1269 }
1270
Felix Held22ca8cb2018-07-29 05:09:44 +02001271 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 {
1273 u8 freq_divisor = 2;
1274 if (info->fsb_frequency == frequency_11(info))
1275 freq_divisor = 3;
1276 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1277 freq_divisor = 1;
1278 else
1279 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001280 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001281 }
1282
1283 if (info->board_lane_delay[3] <= 10) {
1284 if (info->board_lane_delay[3] <= 8)
1285 lane_3_delay = info->board_lane_delay[3];
1286 else
1287 lane_3_delay = 10;
1288 } else {
1289 lane_3_delay = 12;
1290 }
1291 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1292 if (info->clock_speed_index > 1)
1293 cas_latency_derived++;
1294 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001295 MCHBAR32(0x240 + (channel << 10)) =
1296 ((info->clock_speed_index == 0) * 0x11000) |
1297 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1298 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001299 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1300 0x609, 6, 1);
1301 write_500(info, channel,
1302 info->clock_speed_index + 2 * info->cas_latency - 7,
1303 0x601, 6, 1);
1304
Felix Held04be2dd2018-07-29 04:53:22 +02001305 MCHBAR32(0x250 + (channel << 10)) =
1306 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1307 (info->board_lane_delay[7] << 2) |
1308 (info->board_lane_delay[4] << 16) |
1309 (info->board_lane_delay[1] << 25) |
1310 (info->board_lane_delay[1] << 29) | 1;
1311 MCHBAR32(0x254 + (channel << 10)) =
1312 (info->board_lane_delay[1] >> 3) |
1313 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1314 0x80 | (info->board_lane_delay[6] << 1) |
1315 (info->board_lane_delay[2] << 28) |
1316 (cas_latency_derived << 16) | 0x4700000;
1317 MCHBAR32(0x258 + (channel << 10)) =
1318 ((info->board_lane_delay[5] + info->clock_speed_index +
1319 9) << 12) | ((info->clock_speed_index -
1320 info->cas_latency + 12) << 8) |
1321 (info->board_lane_delay[2] << 17) |
1322 (info->board_lane_delay[4] << 24) | 0x47;
1323 MCHBAR32(0x25c + (channel << 10)) =
1324 (info->board_lane_delay[1] << 1) |
1325 (info->board_lane_delay[0] << 8) | 0x1da50000;
1326 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1327 MCHBAR8(0x5f8 + (channel << 10)) =
1328 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001329 }
1330
1331 program_modules_memory_map(info, 1);
1332
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001333 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001334 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1335 MCHBAR16_OR(0x612, 0x100);
1336 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001337 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001338 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001340 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341 }
1342}
1343
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001344#define DEFAULT_PCI_MMIO_SIZE 2048
1345#define HOST_BRIDGE PCI_DEVFN(0, 0)
1346
1347static unsigned int get_mmio_size(void)
1348{
1349 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001350 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001351
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001352 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001353 if (dev)
1354 cfg = dev->chip_info;
1355
1356 /* If this is zero, it just means devicetree.cb didn't set it */
1357 if (!cfg || cfg->pci_mmio_size == 0)
1358 return DEFAULT_PCI_MMIO_SIZE;
1359 else
1360 return cfg->pci_mmio_size;
1361}
1362
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363static void program_total_memory_map(struct raminfo *info)
1364{
Angel Pons9333b742020-07-22 16:04:15 +02001365 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001366 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001367 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001368 unsigned int uma_base_igd;
1369 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001370 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001371 int memory_remap;
1372 unsigned int memory_map[8];
1373 int i;
1374 unsigned int current_limit;
1375 unsigned int tseg_base;
1376 int uma_size_igd = 0, uma_size_gtt = 0;
1377
1378 memset(memory_map, 0, sizeof(memory_map));
1379
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001380 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001381 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001382 gav(t);
1383 const int uma_sizes_gtt[16] =
1384 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1385 /* Igd memory */
1386 const int uma_sizes_igd[16] = {
1387 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1388 256, 512
1389 };
1390
1391 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1392 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1393 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001394
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001395 mmio_size = get_mmio_size();
1396
Angel Pons9333b742020-07-22 16:04:15 +02001397 tom = info->total_memory_mb;
1398 if (tom == 4096)
1399 tom = 4032;
1400 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1401 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1402 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001404 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001406 remap_base = MAX(4096, touud);
1407 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001408 }
Angel Pons9333b742020-07-22 16:04:15 +02001409 if (touud > 4096)
1410 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001411 quickpath_reserved = 0;
1412
Angel Pons3ab19b32020-07-22 16:29:54 +02001413 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001414
Jacob Garber975a7e32019-06-10 16:32:47 -06001415 gav(t);
1416
1417 if (t & 0x800) {
1418 u32 shift = t >> 20;
1419 if (shift == 0)
1420 die("Quickpath value is 0\n");
1421 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001423
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001425 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426
Angel Pons9333b742020-07-22 16:04:15 +02001427 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001428 uma_base_gtt = uma_base_igd - uma_size_gtt;
1429 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1430 if (!memory_remap)
1431 tseg_base -= quickpath_reserved;
1432 tseg_base = ALIGN_DOWN(tseg_base, 8);
1433
Angel Pons16fe1e02020-07-22 16:12:33 +02001434 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1435 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001437 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1438 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001440 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001441
1442 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001443 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1444 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001446 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447
1448 current_limit = 0;
1449 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1450 memory_map[1] = 4096;
1451 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001452 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001453 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1455 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001456 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 }
1458}
1459
1460static void collect_system_info(struct raminfo *info)
1461{
1462 u32 capid0[3];
1463 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001464 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465
1466 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001467 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1468 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 if (!info->memory_reserved_for_heci_mb) {
1471 /* Wait for ME to be ready */
1472 intel_early_me_init();
1473 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1474 }
1475
1476 for (i = 0; i < 3; i++)
1477 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001478 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001479 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1481
1482 if ((capid0[1] >> 11) & 1)
1483 info->uma_enabled = 0;
1484 else
1485 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001486 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1488 info->silicon_revision = 0;
1489
1490 if (capid0[2] & 2) {
1491 info->silicon_revision = 0;
1492 info->max_supported_clock_speed_index = 2;
1493 for (channel = 0; channel < NUM_CHANNELS; channel++)
1494 if (info->populated_ranks[channel][0][0]
1495 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1496 3) {
1497 info->silicon_revision = 2;
1498 info->max_supported_clock_speed_index = 1;
1499 }
1500 } else {
1501 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1502 case 1:
1503 case 2:
1504 info->silicon_revision = 3;
1505 break;
1506 case 3:
1507 info->silicon_revision = 0;
1508 break;
1509 case 0:
1510 info->silicon_revision = 2;
1511 break;
1512 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001513 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001514 case 0x40:
1515 info->silicon_revision = 0;
1516 break;
1517 case 0x48:
1518 info->silicon_revision = 1;
1519 break;
1520 }
1521 }
1522}
1523
1524static void write_training_data(struct raminfo *info)
1525{
1526 int tm, channel, slot, rank, lane;
1527 if (info->revision < 8)
1528 return;
1529
1530 for (tm = 0; tm < 4; tm++)
1531 for (channel = 0; channel < NUM_CHANNELS; channel++)
1532 for (slot = 0; slot < NUM_SLOTS; slot++)
1533 for (rank = 0; rank < NUM_RANKS; rank++)
1534 for (lane = 0; lane < 9; lane++)
1535 write_500(info, channel,
1536 info->
1537 cached_training->
1538 lane_timings[tm]
1539 [channel][slot][rank]
1540 [lane],
1541 get_timing_register_addr
1542 (lane, tm, slot,
1543 rank), 9, 0);
1544 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1545 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1546}
1547
1548static void dump_timings(struct raminfo *info)
1549{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001550 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001551 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001552 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001553 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001554 slot, rank);
1555 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001556 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001558 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559 read_500(info, channel,
1560 get_timing_register_addr
1561 (lane, i, slot, rank),
1562 9),
1563 info->training.
1564 lane_timings[i][channel][slot][rank]
1565 [lane]);
1566 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001567 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568 }
1569 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001570 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001571 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001572 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574}
1575
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001576/* Read timings and other registers that need to be restored verbatim and
1577 put them to CBMEM.
1578 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579static void save_timings(struct raminfo *info)
1580{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 int channel, slot, rank, lane, i;
1583
1584 train = info->training;
1585 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1586 for (i = 0; i < 4; i++)
1587 train.lane_timings[i][channel][slot][rank][lane] =
1588 read_500(info, channel,
1589 get_timing_register_addr(lane, i, slot,
1590 rank), 9);
1591 train.reg_178 = read_1d0(0x178, 7);
1592 train.reg_10b = read_1d0(0x10b, 6);
1593
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001594 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1595 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001596 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001597 train.reg274265[channel][0] = reg32 >> 16;
1598 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001599 train.reg274265[channel][2] =
1600 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001601 }
Felix Held04be2dd2018-07-29 04:53:22 +02001602 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1603 train.reg_6dc = MCHBAR32(0x6dc);
1604 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001605
Arthur Heymansb3282092019-04-14 17:53:28 +02001606 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1607 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001608
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001609 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001610 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1611 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001612}
1613
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001614static const struct ram_training *get_cached_training(void)
1615{
Shelley Chenad9cd682020-07-23 16:10:52 -07001616 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1617 MRC_CACHE_VERSION,
1618 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001619}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620
1621/* FIXME: add timeout. */
1622static void wait_heci_ready(void)
1623{
Felix Held04be2dd2018-07-29 04:53:22 +02001624 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1625 ;
Angel Ponseb537932020-09-14 19:18:11 +02001626
1627 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628}
1629
1630/* FIXME: add timeout. */
1631static void wait_heci_cb_avail(int len)
1632{
1633 union {
1634 struct mei_csr csr;
1635 u32 raw;
1636 } csr;
1637
Felix Held22ca8cb2018-07-29 05:09:44 +02001638 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1639 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640
Angel Ponseb537932020-09-14 19:18:11 +02001641 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001642 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001643 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1644 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001645}
1646
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001647static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648{
1649 int len = (head->length + 3) / 4;
1650 int i;
1651
1652 wait_heci_cb_avail(len + 1);
1653
1654 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001655 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001657 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001658
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001659 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1660 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001661}
1662
Angel Ponseb537932020-09-14 19:18:11 +02001663static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664{
1665 struct mei_header head;
1666 int maxlen;
1667
1668 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001669 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670
1671 while (len) {
1672 int cur = len;
1673 if (cur > maxlen) {
1674 cur = maxlen;
1675 head.is_complete = 0;
1676 } else
1677 head.is_complete = 1;
1678 head.length = cur;
1679 head.reserved = 0;
1680 head.client_address = clientaddress;
1681 head.host_address = hostaddress;
1682 send_heci_packet(&head, (u32 *) msg);
1683 len -= cur;
1684 msg += cur;
1685 }
1686}
1687
1688/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001689static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001690{
1691 union {
1692 struct mei_csr csr;
1693 u32 raw;
1694 } csr;
1695 int i = 0;
1696
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001697 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001698 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001699 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001700 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1701
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001702 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001703 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001704 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705 *packet_size = 0;
1706 return 0;
1707 }
Angel Ponseb537932020-09-14 19:18:11 +02001708 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 *packet_size = 0;
1710 return -1;
1711 }
1712
Angel Ponseb537932020-09-14 19:18:11 +02001713 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001714 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001715 } while (((head->length + 3) >> 2) >
1716 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717
1718 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001719 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001720 *packet_size = head->length;
1721 if (!csr.csr.ready)
1722 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724 return 0;
1725}
1726
1727/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001728static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729{
1730 struct mei_header head;
1731 int current_position;
1732
1733 current_position = 0;
1734 while (1) {
1735 u32 current_size;
1736 current_size = *message_size - current_position;
1737 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001738 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739 &current_size) == -1)
1740 break;
1741 if (!current_size)
1742 break;
1743 current_position += current_size;
1744 if (head.is_complete) {
1745 *message_size = current_position;
1746 return 0;
1747 }
1748
1749 if (current_position >= *message_size)
1750 break;
1751 }
1752 *message_size = 0;
1753 return -1;
1754}
1755
Angel Pons55f11e22020-09-14 19:06:53 +02001756static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001758 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759 u8 group_id;
1760 u8 command;
1761 u8 reserved;
1762 u8 result;
1763 u8 field2;
1764 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001765 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001766
1767 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1768 reply.command = 0;
1769
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001770 struct uma_message {
1771 u8 group_id;
1772 u8 cmd;
1773 u8 reserved;
1774 u8 result;
1775 u32 c2;
1776 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001777 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001778 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001779 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001780 .group_id = 0,
1781 .cmd = MKHI_SET_UMA,
1782 .reserved = 0,
1783 .result = 0,
1784 .c2 = 0x82,
1785 .heci_uma_addr = heci_uma_addr,
1786 .heci_uma_size = heci_uma_size,
1787 .c3 = 0,
1788 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001789 u32 reply_size;
1790
Angel Ponseb537932020-09-14 19:18:11 +02001791 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001792
1793 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001794 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001795 return;
1796
1797 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1798 die("HECI init failed\n");
1799}
1800
1801static void setup_heci_uma(struct raminfo *info)
1802{
Angel Pons298d34d2020-09-14 18:58:53 +02001803 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001804 return;
1805
Angel Pons36592bf2020-09-14 18:52:44 +02001806 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001808 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001809 info->memory_reserved_for_heci_mb)) << 20;
1810
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001811 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001812 if (info->memory_reserved_for_heci_mb) {
Angel Ponsd071c4d2020-09-14 23:51:35 +02001813 DMIBAR32(0x14) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001814 write32(DEFAULT_RCBA + 0x14, read32(DEFAULT_RCBA + 0x14) & ~0x80);
Angel Ponsd071c4d2020-09-14 23:51:35 +02001815 DMIBAR32(0x20) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001816 write32(DEFAULT_RCBA + 0x20, read32(DEFAULT_RCBA + 0x20) & ~0x80);
Angel Ponsd071c4d2020-09-14 23:51:35 +02001817 DMIBAR32(0x2c) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001818 write32(DEFAULT_RCBA + 0x30, read32(DEFAULT_RCBA + 0x30) & ~0x80);
Angel Ponsd071c4d2020-09-14 23:51:35 +02001819 DMIBAR32(0x38) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001820 write32(DEFAULT_RCBA + 0x40, read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001821
Angel Ponseb537932020-09-14 19:18:11 +02001822 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
Angel Ponsd071c4d2020-09-14 23:51:35 +02001823 DMIBAR32(0x38) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001824
Felix Held04be2dd2018-07-29 04:53:22 +02001825 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
Angel Ponsd071c4d2020-09-14 23:51:35 +02001826 DMIBAR16(0x3e) & 2)
Felix Held04be2dd2018-07-29 04:53:22 +02001827 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828 }
1829
Felix Held04be2dd2018-07-29 04:53:22 +02001830 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831
Angel Pons55f11e22020-09-14 19:06:53 +02001832 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001834 pci_write_config32(HECIDEV, 0x10, 0x0);
1835 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836}
1837
1838static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1839{
1840 int ranks_in_channel;
1841 ranks_in_channel = info->populated_ranks[channel][0][0]
1842 + info->populated_ranks[channel][0][1]
1843 + info->populated_ranks[channel][1][0]
1844 + info->populated_ranks[channel][1][1];
1845
1846 /* empty channel */
1847 if (ranks_in_channel == 0)
1848 return 1;
1849
1850 if (ranks_in_channel != ranks)
1851 return 0;
1852 /* single slot */
1853 if (info->populated_ranks[channel][0][0] !=
1854 info->populated_ranks[channel][1][0])
1855 return 1;
1856 if (info->populated_ranks[channel][0][1] !=
1857 info->populated_ranks[channel][1][1])
1858 return 1;
1859 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1860 return 0;
1861 if (info->density[channel][0] != info->density[channel][1])
1862 return 0;
1863 return 1;
1864}
1865
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866static void read_4090(struct raminfo *info)
1867{
1868 int i, channel, slot, rank, lane;
1869 for (i = 0; i < 2; i++)
1870 for (slot = 0; slot < NUM_SLOTS; slot++)
1871 for (rank = 0; rank < NUM_RANKS; rank++)
1872 for (lane = 0; lane < 9; lane++)
1873 info->training.
1874 lane_timings[0][i][slot][rank][lane]
1875 = 32;
1876
1877 for (i = 1; i < 4; i++)
1878 for (channel = 0; channel < NUM_CHANNELS; channel++)
1879 for (slot = 0; slot < NUM_SLOTS; slot++)
1880 for (rank = 0; rank < NUM_RANKS; rank++)
1881 for (lane = 0; lane < 9; lane++) {
1882 info->training.
1883 lane_timings[i][channel]
1884 [slot][rank][lane] =
1885 read_500(info, channel,
1886 get_timing_register_addr
1887 (lane, i, slot,
1888 rank), 9)
1889 + (i == 1) * 11; // !!!!
1890 }
1891
1892}
1893
1894static u32 get_etalon2(int flip, u32 addr)
1895{
1896 const u16 invmask[] = {
1897 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1898 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1899 };
1900 u32 ret;
1901 u32 comp4 = addr / 480;
1902 addr %= 480;
1903 u32 comp1 = addr & 0xf;
1904 u32 comp2 = (addr >> 4) & 1;
1905 u32 comp3 = addr >> 5;
1906
1907 if (comp4)
1908 ret = 0x1010101 << (comp4 - 1);
1909 else
1910 ret = 0;
1911 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1912 ret = ~ret;
1913
1914 return ret;
1915}
1916
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001917static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001918{
1919 msr_t msr = {.lo = 0, .hi = 0 };
1920
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001921 wrmsr(MTRR_PHYS_BASE(3), msr);
1922 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001923}
1924
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001925static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001926{
1927 msr_t msr;
1928 msr.lo = base | MTRR_TYPE_WRPROT;
1929 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001930 wrmsr(MTRR_PHYS_BASE(3), msr);
1931 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001932 & 0xffffffff);
1933 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001934 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001935}
1936
1937static void flush_cache(u32 start, u32 size)
1938{
1939 u32 end;
1940 u32 addr;
1941
1942 end = start + (ALIGN_DOWN(size + 4096, 4096));
1943 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001944 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945}
1946
1947static void clear_errors(void)
1948{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001949 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001950}
1951
1952static void write_testing(struct raminfo *info, int totalrank, int flip)
1953{
1954 int nwrites = 0;
1955 /* in 8-byte units. */
1956 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001957 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001959 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001960 for (offset = 0; offset < 9 * 480; offset += 2) {
1961 write32(base + offset * 8, get_etalon2(flip, offset));
1962 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1963 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1964 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1965 nwrites += 4;
1966 if (nwrites >= 320) {
1967 clear_errors();
1968 nwrites = 0;
1969 }
1970 }
1971}
1972
1973static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1974{
1975 u8 failmask = 0;
1976 int i;
1977 int comp1, comp2, comp3;
1978 u32 failxor[2] = { 0, 0 };
1979
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001980 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001981
1982 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1983 for (comp1 = 0; comp1 < 4; comp1++)
1984 for (comp2 = 0; comp2 < 60; comp2++) {
1985 u32 re[4];
1986 u32 curroffset =
1987 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1988 read128((total_rank << 28) | (curroffset << 3),
1989 (u64 *) re);
1990 failxor[0] |=
1991 get_etalon2(flip, curroffset) ^ re[0];
1992 failxor[1] |=
1993 get_etalon2(flip, curroffset) ^ re[1];
1994 failxor[0] |=
1995 get_etalon2(flip, curroffset | 1) ^ re[2];
1996 failxor[1] |=
1997 get_etalon2(flip, curroffset | 1) ^ re[3];
1998 }
1999 for (i = 0; i < 8; i++)
2000 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2001 failmask |= 1 << i;
2002 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002003 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002004 flush_cache((total_rank << 28), 1728 * 5 * 4);
2005 return failmask;
2006}
2007
2008const u32 seed1[0x18] = {
2009 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2010 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2011 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2012 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2013 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2014 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2015};
2016
2017static u32 get_seed2(int a, int b)
2018{
2019 const u32 seed2[5] = {
2020 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2021 0x5b6db6db,
2022 };
2023 u32 r;
2024 r = seed2[(a + (a >= 10)) / 5];
2025 return b ? ~r : r;
2026}
2027
2028static int make_shift(int comp2, int comp5, int x)
2029{
2030 const u8 seed3[32] = {
2031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2032 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2033 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2034 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2035 };
2036
2037 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2038}
2039
2040static u32 get_etalon(int flip, u32 addr)
2041{
2042 u32 mask_byte = 0;
2043 int comp1 = (addr >> 1) & 1;
2044 int comp2 = (addr >> 3) & 0x1f;
2045 int comp3 = (addr >> 8) & 0xf;
2046 int comp4 = (addr >> 12) & 0xf;
2047 int comp5 = (addr >> 16) & 0x1f;
2048 u32 mask_bit = ~(0x10001 << comp3);
2049 u32 part1;
2050 u32 part2;
2051 int byte;
2052
2053 part2 =
2054 ((seed1[comp5] >>
2055 make_shift(comp2, comp5,
2056 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2057 part1 =
2058 ((seed1[comp5] >>
2059 make_shift(comp2, comp5,
2060 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2061
2062 for (byte = 0; byte < 4; byte++)
2063 if ((get_seed2(comp5, comp4) >>
2064 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2065 mask_byte |= 0xff << (8 * byte);
2066
2067 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2068 (comp3 + 16));
2069}
2070
2071static void
2072write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2073 char flip)
2074{
2075 int i;
2076 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002077 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2078 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002079}
2080
2081static u8
2082check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2083 char flip)
2084{
2085 u8 failmask = 0;
2086 u32 failxor[2];
2087 int i;
2088 int comp1, comp2, comp3;
2089
2090 failxor[0] = 0;
2091 failxor[1] = 0;
2092
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002093 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002094 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2095 for (comp1 = 0; comp1 < 16; comp1++)
2096 for (comp2 = 0; comp2 < 64; comp2++) {
2097 u32 addr =
2098 (totalrank << 28) | (region << 25) | (block
2099 << 16)
2100 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2101 2);
2102 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002103 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002104 }
2105 for (i = 0; i < 8; i++)
2106 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2107 failmask |= 1 << i;
2108 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002109 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002110 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2111 return failmask;
2112}
2113
2114static int check_bounded(unsigned short *vals, u16 bound)
2115{
2116 int i;
2117
2118 for (i = 0; i < 8; i++)
2119 if (vals[i] < bound)
2120 return 0;
2121 return 1;
2122}
2123
2124enum state {
2125 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2126};
2127
2128static int validate_state(enum state *in)
2129{
2130 int i;
2131 for (i = 0; i < 8; i++)
2132 if (in[i] != COMPLETE)
2133 return 0;
2134 return 1;
2135}
2136
2137static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002138do_fsm(enum state *state, u16 *counter,
2139 u8 fail_mask, int margin, int uplimit,
2140 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002141{
2142 int lane;
2143
2144 for (lane = 0; lane < 8; lane++) {
2145 int is_fail = (fail_mask >> lane) & 1;
2146 switch (state[lane]) {
2147 case BEFORE_USABLE:
2148 if (!is_fail) {
2149 counter[lane] = 1;
2150 state[lane] = AT_USABLE;
2151 break;
2152 }
2153 counter[lane] = 0;
2154 state[lane] = BEFORE_USABLE;
2155 break;
2156 case AT_USABLE:
2157 if (!is_fail) {
2158 ++counter[lane];
2159 if (counter[lane] >= margin) {
2160 state[lane] = AT_MARGIN;
2161 res_low[lane] = val - margin + 1;
2162 break;
2163 }
2164 state[lane] = 1;
2165 break;
2166 }
2167 counter[lane] = 0;
2168 state[lane] = BEFORE_USABLE;
2169 break;
2170 case AT_MARGIN:
2171 if (is_fail) {
2172 state[lane] = COMPLETE;
2173 res_high[lane] = val - 1;
2174 } else {
2175 counter[lane]++;
2176 state[lane] = AT_MARGIN;
2177 if (val == uplimit) {
2178 state[lane] = COMPLETE;
2179 res_high[lane] = uplimit;
2180 }
2181 }
2182 break;
2183 case COMPLETE:
2184 break;
2185 }
2186 }
2187}
2188
2189static void
2190train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2191 u8 total_rank, u8 reg_178, int first_run, int niter,
2192 timing_bounds_t * timings)
2193{
2194 int lane;
2195 enum state state[8];
2196 u16 count[8];
2197 u8 lower_usable[8];
2198 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002199 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002200 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002201 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002202
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002203 for (i = 0; i < 8; i++)
2204 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002205
2206 if (!first_run) {
2207 int is_all_ok = 1;
2208 for (lane = 0; lane < 8; lane++)
2209 if (timings[reg_178][channel][slot][rank][lane].
2210 smallest ==
2211 timings[reg_178][channel][slot][rank][lane].
2212 largest) {
2213 timings[reg_178][channel][slot][rank][lane].
2214 smallest = 0;
2215 timings[reg_178][channel][slot][rank][lane].
2216 largest = 0;
2217 is_all_ok = 0;
2218 }
2219 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002220 for (i = 0; i < 8; i++)
2221 state[i] = COMPLETE;
2222 }
2223 }
2224
2225 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2226 u8 failmask = 0;
2227 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2228 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2229 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002230 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002231 do_fsm(state, count, failmask, 5, 47, lower_usable,
2232 upper_usable, reg1b3);
2233 }
2234
2235 if (reg1b3) {
2236 write_1d0(0, 0x1b3, 6, 1);
2237 write_1d0(0, 0x1a3, 6, 1);
2238 for (lane = 0; lane < 8; lane++) {
2239 if (state[lane] == COMPLETE) {
2240 timings[reg_178][channel][slot][rank][lane].
2241 smallest =
2242 lower_usable[lane] +
2243 (info->training.
2244 lane_timings[0][channel][slot][rank][lane]
2245 & 0x3F) - 32;
2246 timings[reg_178][channel][slot][rank][lane].
2247 largest =
2248 upper_usable[lane] +
2249 (info->training.
2250 lane_timings[0][channel][slot][rank][lane]
2251 & 0x3F) - 32;
2252 }
2253 }
2254 }
2255
2256 if (!first_run) {
2257 for (lane = 0; lane < 8; lane++)
2258 if (state[lane] == COMPLETE) {
2259 write_500(info, channel,
2260 timings[reg_178][channel][slot][rank]
2261 [lane].smallest,
2262 get_timing_register_addr(lane, 0,
2263 slot, rank),
2264 9, 1);
2265 write_500(info, channel,
2266 timings[reg_178][channel][slot][rank]
2267 [lane].smallest +
2268 info->training.
2269 lane_timings[1][channel][slot][rank]
2270 [lane]
2271 -
2272 info->training.
2273 lane_timings[0][channel][slot][rank]
2274 [lane], get_timing_register_addr(lane,
2275 1,
2276 slot,
2277 rank),
2278 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002279 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002280 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002281 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002282
2283 do {
2284 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002285 for (i = 0; i < niter; i++) {
2286 if (failmask == 0xFF)
2287 break;
2288 failmask |=
2289 check_testing_type2(info, total_rank, 2, i,
2290 0);
2291 failmask |=
2292 check_testing_type2(info, total_rank, 3, i,
2293 1);
2294 }
Felix Held04be2dd2018-07-29 04:53:22 +02002295 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002297 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002298 if ((1 << lane) & failmask) {
2299 if (timings[reg_178][channel]
2300 [slot][rank][lane].
2301 largest <=
2302 timings[reg_178][channel]
2303 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002304 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002305 [lane] = -1;
2306 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002307 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308 [lane] = 0;
2309 timings[reg_178]
2310 [channel][slot]
2311 [rank][lane].
2312 smallest++;
2313 write_500(info, channel,
2314 timings
2315 [reg_178]
2316 [channel]
2317 [slot][rank]
2318 [lane].
2319 smallest,
2320 get_timing_register_addr
2321 (lane, 0,
2322 slot, rank),
2323 9, 1);
2324 write_500(info, channel,
2325 timings
2326 [reg_178]
2327 [channel]
2328 [slot][rank]
2329 [lane].
2330 smallest +
2331 info->
2332 training.
2333 lane_timings
2334 [1][channel]
2335 [slot][rank]
2336 [lane]
2337 -
2338 info->
2339 training.
2340 lane_timings
2341 [0][channel]
2342 [slot][rank]
2343 [lane],
2344 get_timing_register_addr
2345 (lane, 1,
2346 slot, rank),
2347 9, 1);
2348 }
2349 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002350 num_successfully_checked[lane]
2351 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002352 }
2353 }
Felix Held04be2dd2018-07-29 04:53:22 +02002354 while (!check_bounded(num_successfully_checked, 2))
2355 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002356
2357 for (lane = 0; lane < 8; lane++)
2358 if (state[lane] == COMPLETE) {
2359 write_500(info, channel,
2360 timings[reg_178][channel][slot][rank]
2361 [lane].largest,
2362 get_timing_register_addr(lane, 0,
2363 slot, rank),
2364 9, 1);
2365 write_500(info, channel,
2366 timings[reg_178][channel][slot][rank]
2367 [lane].largest +
2368 info->training.
2369 lane_timings[1][channel][slot][rank]
2370 [lane]
2371 -
2372 info->training.
2373 lane_timings[0][channel][slot][rank]
2374 [lane], get_timing_register_addr(lane,
2375 1,
2376 slot,
2377 rank),
2378 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002379 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002381 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002382
2383 do {
2384 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002385 for (i = 0; i < niter; i++) {
2386 if (failmask == 0xFF)
2387 break;
2388 failmask |=
2389 check_testing_type2(info, total_rank, 2, i,
2390 0);
2391 failmask |=
2392 check_testing_type2(info, total_rank, 3, i,
2393 1);
2394 }
2395
Felix Held04be2dd2018-07-29 04:53:22 +02002396 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002398 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399 if ((1 << lane) & failmask) {
2400 if (timings[reg_178][channel]
2401 [slot][rank][lane].
2402 largest <=
2403 timings[reg_178][channel]
2404 [slot][rank][lane].
2405 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002406 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002407 [lane] = -1;
2408 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002409 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002410 [lane] = 0;
2411 timings[reg_178]
2412 [channel][slot]
2413 [rank][lane].
2414 largest--;
2415 write_500(info, channel,
2416 timings
2417 [reg_178]
2418 [channel]
2419 [slot][rank]
2420 [lane].
2421 largest,
2422 get_timing_register_addr
2423 (lane, 0,
2424 slot, rank),
2425 9, 1);
2426 write_500(info, channel,
2427 timings
2428 [reg_178]
2429 [channel]
2430 [slot][rank]
2431 [lane].
2432 largest +
2433 info->
2434 training.
2435 lane_timings
2436 [1][channel]
2437 [slot][rank]
2438 [lane]
2439 -
2440 info->
2441 training.
2442 lane_timings
2443 [0][channel]
2444 [slot][rank]
2445 [lane],
2446 get_timing_register_addr
2447 (lane, 1,
2448 slot, rank),
2449 9, 1);
2450 }
2451 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002452 num_successfully_checked[lane]
2453 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002454 }
2455 }
2456 }
Felix Held04be2dd2018-07-29 04:53:22 +02002457 while (!check_bounded(num_successfully_checked, 3))
2458 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002459
2460 for (lane = 0; lane < 8; lane++) {
2461 write_500(info, channel,
2462 info->training.
2463 lane_timings[0][channel][slot][rank][lane],
2464 get_timing_register_addr(lane, 0, slot, rank),
2465 9, 1);
2466 write_500(info, channel,
2467 info->training.
2468 lane_timings[1][channel][slot][rank][lane],
2469 get_timing_register_addr(lane, 1, slot, rank),
2470 9, 1);
2471 if (timings[reg_178][channel][slot][rank][lane].
2472 largest <=
2473 timings[reg_178][channel][slot][rank][lane].
2474 smallest) {
2475 timings[reg_178][channel][slot][rank][lane].
2476 largest = 0;
2477 timings[reg_178][channel][slot][rank][lane].
2478 smallest = 0;
2479 }
2480 }
2481 }
2482}
2483
2484static void set_10b(struct raminfo *info, u8 val)
2485{
2486 int channel;
2487 int slot, rank;
2488 int lane;
2489
2490 if (read_1d0(0x10b, 6) == val)
2491 return;
2492
2493 write_1d0(val, 0x10b, 6, 1);
2494
2495 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2496 u16 reg_500;
2497 reg_500 = read_500(info, channel,
2498 get_timing_register_addr(lane, 0, slot,
2499 rank), 9);
2500 if (val == 1) {
2501 if (lut16[info->clock_speed_index] <= reg_500)
2502 reg_500 -= lut16[info->clock_speed_index];
2503 else
2504 reg_500 = 0;
2505 } else {
2506 reg_500 += lut16[info->clock_speed_index];
2507 }
2508 write_500(info, channel, reg_500,
2509 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2510 }
2511}
2512
2513static void set_ecc(int onoff)
2514{
2515 int channel;
2516 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2517 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002518 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002519 if (onoff)
2520 t |= 1;
2521 else
2522 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002523 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002524 }
2525}
2526
2527static void set_178(u8 val)
2528{
2529 if (val >= 31)
2530 val = val - 31;
2531 else
2532 val = 63 - val;
2533
2534 write_1d0(2 * val, 0x178, 7, 1);
2535}
2536
2537static void
2538write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2539 int type)
2540{
2541 int lane;
2542
2543 for (lane = 0; lane < 8; lane++)
2544 write_500(info, channel,
2545 info->training.
2546 lane_timings[type][channel][slot][rank][lane],
2547 get_timing_register_addr(lane, type, slot, rank), 9,
2548 0);
2549}
2550
2551static void
2552try_timing_offsets(struct raminfo *info, int channel,
2553 int slot, int rank, int totalrank)
2554{
2555 u16 count[8];
2556 enum state state[8];
2557 u8 lower_usable[8], upper_usable[8];
2558 int lane;
2559 int i;
2560 int flip = 1;
2561 int timing_offset;
2562
2563 for (i = 0; i < 8; i++)
2564 state[i] = BEFORE_USABLE;
2565
2566 memset(count, 0, sizeof(count));
2567
2568 for (lane = 0; lane < 8; lane++)
2569 write_500(info, channel,
2570 info->training.
2571 lane_timings[2][channel][slot][rank][lane] + 32,
2572 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2573
2574 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2575 timing_offset++) {
2576 u8 failmask;
2577 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2578 failmask = 0;
2579 for (i = 0; i < 2 && failmask != 0xff; i++) {
2580 flip = !flip;
2581 write_testing(info, totalrank, flip);
2582 failmask |= check_testing(info, totalrank, flip);
2583 }
2584 do_fsm(state, count, failmask, 10, 63, lower_usable,
2585 upper_usable, timing_offset);
2586 }
2587 write_1d0(0, 0x1bb, 6, 1);
2588 dump_timings(info);
2589 if (!validate_state(state))
2590 die("Couldn't discover DRAM timings (1)\n");
2591
2592 for (lane = 0; lane < 8; lane++) {
2593 u8 bias = 0;
2594
2595 if (info->silicon_revision) {
2596 int usable_length;
2597
2598 usable_length = upper_usable[lane] - lower_usable[lane];
2599 if (usable_length >= 20) {
2600 bias = usable_length / 2 - 10;
2601 if (bias >= 2)
2602 bias = 2;
2603 }
2604 }
2605 write_500(info, channel,
2606 info->training.
2607 lane_timings[2][channel][slot][rank][lane] +
2608 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2609 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2610 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2611 info->training.lane_timings[2][channel][slot][rank][lane] +
2612 lower_usable[lane];
2613 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2614 info->training.lane_timings[2][channel][slot][rank][lane] +
2615 upper_usable[lane];
2616 info->training.timing2_offset[channel][slot][rank][lane] =
2617 info->training.lane_timings[2][channel][slot][rank][lane];
2618 }
2619}
2620
2621static u8
2622choose_training(struct raminfo *info, int channel, int slot, int rank,
2623 int lane, timing_bounds_t * timings, u8 center_178)
2624{
2625 u16 central_weight;
2626 u16 side_weight;
2627 unsigned int sum = 0, count = 0;
2628 u8 span;
2629 u8 lower_margin, upper_margin;
2630 u8 reg_178;
2631 u8 result;
2632
2633 span = 12;
2634 central_weight = 20;
2635 side_weight = 20;
2636 if (info->silicon_revision == 1 && channel == 1) {
2637 central_weight = 5;
2638 side_weight = 20;
2639 if ((info->
2640 populated_ranks_mask[1] ^ (info->
2641 populated_ranks_mask[1] >> 2)) &
2642 1)
2643 span = 18;
2644 }
2645 if ((info->populated_ranks_mask[0] & 5) == 5) {
2646 central_weight = 20;
2647 side_weight = 20;
2648 }
2649 if (info->clock_speed_index >= 2
2650 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2651 if (info->silicon_revision == 1) {
2652 switch (channel) {
2653 case 0:
2654 if (lane == 1) {
2655 central_weight = 10;
2656 side_weight = 20;
2657 }
2658 break;
2659 case 1:
2660 if (lane == 6) {
2661 side_weight = 5;
2662 central_weight = 20;
2663 }
2664 break;
2665 }
2666 }
2667 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2668 side_weight = 5;
2669 central_weight = 20;
2670 }
2671 }
2672 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2673 reg_178 += span) {
2674 u8 smallest;
2675 u8 largest;
2676 largest = timings[reg_178][channel][slot][rank][lane].largest;
2677 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2678 if (largest - smallest + 1 >= 5) {
2679 unsigned int weight;
2680 if (reg_178 == center_178)
2681 weight = central_weight;
2682 else
2683 weight = side_weight;
2684 sum += weight * (largest + smallest);
2685 count += weight;
2686 }
2687 }
2688 dump_timings(info);
2689 if (count == 0)
2690 die("Couldn't discover DRAM timings (2)\n");
2691 result = sum / (2 * count);
2692 lower_margin =
2693 result - timings[center_178][channel][slot][rank][lane].smallest;
2694 upper_margin =
2695 timings[center_178][channel][slot][rank][lane].largest - result;
2696 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002697 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002698 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002699 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002700 return result;
2701}
2702
2703#define STANDARD_MIN_MARGIN 5
2704
2705static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2706{
2707 u16 margin[64];
2708 int lane, rank, slot, channel;
2709 u8 reg178;
2710 int count = 0, sum = 0;
2711
2712 for (reg178 = reg178_min[info->clock_speed_index];
2713 reg178 < reg178_max[info->clock_speed_index];
2714 reg178 += reg178_step[info->clock_speed_index]) {
2715 margin[reg178] = -1;
2716 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2717 int curmargin =
2718 timings[reg178][channel][slot][rank][lane].largest -
2719 timings[reg178][channel][slot][rank][lane].
2720 smallest + 1;
2721 if (curmargin < margin[reg178])
2722 margin[reg178] = curmargin;
2723 }
2724 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2725 u16 weight;
2726 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2727 sum += weight * reg178;
2728 count += weight;
2729 }
2730 }
2731 dump_timings(info);
2732 if (count == 0)
2733 die("Couldn't discover DRAM timings (3)\n");
2734
2735 u8 threshold;
2736
2737 for (threshold = 30; threshold >= 5; threshold--) {
2738 int usable_length = 0;
2739 int smallest_fount = 0;
2740 for (reg178 = reg178_min[info->clock_speed_index];
2741 reg178 < reg178_max[info->clock_speed_index];
2742 reg178 += reg178_step[info->clock_speed_index])
2743 if (margin[reg178] >= threshold) {
2744 usable_length +=
2745 reg178_step[info->clock_speed_index];
2746 info->training.reg178_largest =
2747 reg178 -
2748 2 * reg178_step[info->clock_speed_index];
2749
2750 if (!smallest_fount) {
2751 smallest_fount = 1;
2752 info->training.reg178_smallest =
2753 reg178 +
2754 reg178_step[info->
2755 clock_speed_index];
2756 }
2757 }
2758 if (usable_length >= 0x21)
2759 break;
2760 }
2761
2762 return sum / count;
2763}
2764
2765static int check_cached_sanity(struct raminfo *info)
2766{
2767 int lane;
2768 int slot, rank;
2769 int channel;
2770
2771 if (!info->cached_training)
2772 return 0;
2773
2774 for (channel = 0; channel < NUM_CHANNELS; channel++)
2775 for (slot = 0; slot < NUM_SLOTS; slot++)
2776 for (rank = 0; rank < NUM_RANKS; rank++)
2777 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2778 u16 cached_value, estimation_value;
2779 cached_value =
2780 info->cached_training->
2781 lane_timings[1][channel][slot][rank]
2782 [lane];
2783 if (cached_value >= 0x18
2784 && cached_value <= 0x1E7) {
2785 estimation_value =
2786 info->training.
2787 lane_timings[1][channel]
2788 [slot][rank][lane];
2789 if (estimation_value <
2790 cached_value - 24)
2791 return 0;
2792 if (estimation_value >
2793 cached_value + 24)
2794 return 0;
2795 }
2796 }
2797 return 1;
2798}
2799
2800static int try_cached_training(struct raminfo *info)
2801{
2802 u8 saved_243[2];
2803 u8 tm;
2804
2805 int channel, slot, rank, lane;
2806 int flip = 1;
2807 int i, j;
2808
2809 if (!check_cached_sanity(info))
2810 return 0;
2811
2812 info->training.reg178_center = info->cached_training->reg178_center;
2813 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2814 info->training.reg178_largest = info->cached_training->reg178_largest;
2815 memcpy(&info->training.timing_bounds,
2816 &info->cached_training->timing_bounds,
2817 sizeof(info->training.timing_bounds));
2818 memcpy(&info->training.timing_offset,
2819 &info->cached_training->timing_offset,
2820 sizeof(info->training.timing_offset));
2821
2822 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002823 saved_243[0] = MCHBAR8(0x243);
2824 saved_243[1] = MCHBAR8(0x643);
2825 MCHBAR8(0x243) = saved_243[0] | 2;
2826 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002827 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002828 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002829 if (read_1d0(0x10b, 6) & 1)
2830 set_10b(info, 0);
2831 for (tm = 0; tm < 2; tm++) {
2832 int totalrank;
2833
2834 set_178(tm ? info->cached_training->reg178_largest : info->
2835 cached_training->reg178_smallest);
2836
2837 totalrank = 0;
2838 /* Check timing ranges. With i == 0 we check smallest one and with
2839 i == 1 the largest bound. With j == 0 we check that on the bound
2840 it still works whereas with j == 1 we check that just outside of
2841 bound we fail.
2842 */
2843 FOR_POPULATED_RANKS_BACKWARDS {
2844 for (i = 0; i < 2; i++) {
2845 for (lane = 0; lane < 8; lane++) {
2846 write_500(info, channel,
2847 info->cached_training->
2848 timing2_bounds[channel][slot]
2849 [rank][lane][i],
2850 get_timing_register_addr(lane,
2851 3,
2852 slot,
2853 rank),
2854 9, 1);
2855
2856 if (!i)
2857 write_500(info, channel,
2858 info->
2859 cached_training->
2860 timing2_offset
2861 [channel][slot][rank]
2862 [lane],
2863 get_timing_register_addr
2864 (lane, 2, slot, rank),
2865 9, 1);
2866 write_500(info, channel,
2867 i ? info->cached_training->
2868 timing_bounds[tm][channel]
2869 [slot][rank][lane].
2870 largest : info->
2871 cached_training->
2872 timing_bounds[tm][channel]
2873 [slot][rank][lane].smallest,
2874 get_timing_register_addr(lane,
2875 0,
2876 slot,
2877 rank),
2878 9, 1);
2879 write_500(info, channel,
2880 info->cached_training->
2881 timing_offset[channel][slot]
2882 [rank][lane] +
2883 (i ? info->cached_training->
2884 timing_bounds[tm][channel]
2885 [slot][rank][lane].
2886 largest : info->
2887 cached_training->
2888 timing_bounds[tm][channel]
2889 [slot][rank][lane].
2890 smallest) - 64,
2891 get_timing_register_addr(lane,
2892 1,
2893 slot,
2894 rank),
2895 9, 1);
2896 }
2897 for (j = 0; j < 2; j++) {
2898 u8 failmask;
2899 u8 expected_failmask;
2900 char reg1b3;
2901
2902 reg1b3 = (j == 1) + 4;
2903 reg1b3 =
2904 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2905 write_1d0(reg1b3, 0x1bb, 6, 1);
2906 write_1d0(reg1b3, 0x1b3, 6, 1);
2907 write_1d0(reg1b3, 0x1a3, 6, 1);
2908
2909 flip = !flip;
2910 write_testing(info, totalrank, flip);
2911 failmask =
2912 check_testing(info, totalrank,
2913 flip);
2914 expected_failmask =
2915 j == 0 ? 0x00 : 0xff;
2916 if (failmask != expected_failmask)
2917 goto fail;
2918 }
2919 }
2920 totalrank++;
2921 }
2922 }
2923
2924 set_178(info->cached_training->reg178_center);
2925 if (info->use_ecc)
2926 set_ecc(1);
2927 write_training_data(info);
2928 write_1d0(0, 322, 3, 1);
2929 info->training = *info->cached_training;
2930
2931 write_1d0(0, 0x1bb, 6, 1);
2932 write_1d0(0, 0x1b3, 6, 1);
2933 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002934 MCHBAR8(0x243) = saved_243[0];
2935 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002936
2937 return 1;
2938
2939fail:
2940 FOR_POPULATED_RANKS {
2941 write_500_timings_type(info, channel, slot, rank, 1);
2942 write_500_timings_type(info, channel, slot, rank, 2);
2943 write_500_timings_type(info, channel, slot, rank, 3);
2944 }
2945
2946 write_1d0(0, 0x1bb, 6, 1);
2947 write_1d0(0, 0x1b3, 6, 1);
2948 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002949 MCHBAR8(0x243) = saved_243[0];
2950 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002951
2952 return 0;
2953}
2954
2955static void do_ram_training(struct raminfo *info)
2956{
2957 u8 saved_243[2];
2958 int totalrank = 0;
2959 u8 reg_178;
2960 int niter;
2961
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002962 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002963 int lane, rank, slot, channel;
2964 u8 reg178_center;
2965
2966 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002967 saved_243[0] = MCHBAR8(0x243);
2968 saved_243[1] = MCHBAR8(0x643);
2969 MCHBAR8(0x243) = saved_243[0] | 2;
2970 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002971 switch (info->clock_speed_index) {
2972 case 0:
2973 niter = 5;
2974 break;
2975 case 1:
2976 niter = 10;
2977 break;
2978 default:
2979 niter = 19;
2980 break;
2981 }
2982 set_ecc(0);
2983
2984 FOR_POPULATED_RANKS_BACKWARDS {
2985 int i;
2986
2987 write_500_timings_type(info, channel, slot, rank, 0);
2988
2989 write_testing(info, totalrank, 0);
2990 for (i = 0; i < niter; i++) {
2991 write_testing_type2(info, totalrank, 2, i, 0);
2992 write_testing_type2(info, totalrank, 3, i, 1);
2993 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002994 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002995 totalrank++;
2996 }
2997
2998 if (reg178_min[info->clock_speed_index] <
2999 reg178_max[info->clock_speed_index])
3000 memset(timings[reg178_min[info->clock_speed_index]], 0,
3001 sizeof(timings[0]) *
3002 (reg178_max[info->clock_speed_index] -
3003 reg178_min[info->clock_speed_index]));
3004 for (reg_178 = reg178_min[info->clock_speed_index];
3005 reg_178 < reg178_max[info->clock_speed_index];
3006 reg_178 += reg178_step[info->clock_speed_index]) {
3007 totalrank = 0;
3008 set_178(reg_178);
3009 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3010 for (slot = 0; slot < NUM_SLOTS; slot++)
3011 for (rank = 0; rank < NUM_RANKS; rank++) {
3012 memset(&timings[reg_178][channel][slot]
3013 [rank][0].smallest, 0, 16);
3014 if (info->
3015 populated_ranks[channel][slot]
3016 [rank]) {
3017 train_ram_at_178(info, channel,
3018 slot, rank,
3019 totalrank,
3020 reg_178, 1,
3021 niter,
3022 timings);
3023 totalrank++;
3024 }
3025 }
3026 }
3027
3028 reg178_center = choose_reg178(info, timings);
3029
3030 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3031 info->training.timing_bounds[0][channel][slot][rank][lane].
3032 smallest =
3033 timings[info->training.
3034 reg178_smallest][channel][slot][rank][lane].
3035 smallest;
3036 info->training.timing_bounds[0][channel][slot][rank][lane].
3037 largest =
3038 timings[info->training.
3039 reg178_smallest][channel][slot][rank][lane].largest;
3040 info->training.timing_bounds[1][channel][slot][rank][lane].
3041 smallest =
3042 timings[info->training.
3043 reg178_largest][channel][slot][rank][lane].smallest;
3044 info->training.timing_bounds[1][channel][slot][rank][lane].
3045 largest =
3046 timings[info->training.
3047 reg178_largest][channel][slot][rank][lane].largest;
3048 info->training.timing_offset[channel][slot][rank][lane] =
3049 info->training.lane_timings[1][channel][slot][rank][lane]
3050 -
3051 info->training.lane_timings[0][channel][slot][rank][lane] +
3052 64;
3053 }
3054
3055 if (info->silicon_revision == 1
3056 && (info->
3057 populated_ranks_mask[1] ^ (info->
3058 populated_ranks_mask[1] >> 2)) & 1) {
3059 int ranks_after_channel1;
3060
3061 totalrank = 0;
3062 for (reg_178 = reg178_center - 18;
3063 reg_178 <= reg178_center + 18; reg_178 += 18) {
3064 totalrank = 0;
3065 set_178(reg_178);
3066 for (slot = 0; slot < NUM_SLOTS; slot++)
3067 for (rank = 0; rank < NUM_RANKS; rank++) {
3068 if (info->
3069 populated_ranks[1][slot][rank]) {
3070 train_ram_at_178(info, 1, slot,
3071 rank,
3072 totalrank,
3073 reg_178, 0,
3074 niter,
3075 timings);
3076 totalrank++;
3077 }
3078 }
3079 }
3080 ranks_after_channel1 = totalrank;
3081
3082 for (reg_178 = reg178_center - 12;
3083 reg_178 <= reg178_center + 12; reg_178 += 12) {
3084 totalrank = ranks_after_channel1;
3085 set_178(reg_178);
3086 for (slot = 0; slot < NUM_SLOTS; slot++)
3087 for (rank = 0; rank < NUM_RANKS; rank++)
3088 if (info->
3089 populated_ranks[0][slot][rank]) {
3090 train_ram_at_178(info, 0, slot,
3091 rank,
3092 totalrank,
3093 reg_178, 0,
3094 niter,
3095 timings);
3096 totalrank++;
3097 }
3098
3099 }
3100 } else {
3101 for (reg_178 = reg178_center - 12;
3102 reg_178 <= reg178_center + 12; reg_178 += 12) {
3103 totalrank = 0;
3104 set_178(reg_178);
3105 FOR_POPULATED_RANKS_BACKWARDS {
3106 train_ram_at_178(info, channel, slot, rank,
3107 totalrank, reg_178, 0, niter,
3108 timings);
3109 totalrank++;
3110 }
3111 }
3112 }
3113
3114 set_178(reg178_center);
3115 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3116 u16 tm0;
3117
3118 tm0 =
3119 choose_training(info, channel, slot, rank, lane, timings,
3120 reg178_center);
3121 write_500(info, channel, tm0,
3122 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3123 write_500(info, channel,
3124 tm0 +
3125 info->training.
3126 lane_timings[1][channel][slot][rank][lane] -
3127 info->training.
3128 lane_timings[0][channel][slot][rank][lane],
3129 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3130 }
3131
3132 totalrank = 0;
3133 FOR_POPULATED_RANKS_BACKWARDS {
3134 try_timing_offsets(info, channel, slot, rank, totalrank);
3135 totalrank++;
3136 }
Felix Held04be2dd2018-07-29 04:53:22 +02003137 MCHBAR8(0x243) = saved_243[0];
3138 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003139 write_1d0(0, 0x142, 3, 1);
3140 info->training.reg178_center = reg178_center;
3141}
3142
3143static void ram_training(struct raminfo *info)
3144{
3145 u16 saved_fc4;
3146
Felix Held04be2dd2018-07-29 04:53:22 +02003147 saved_fc4 = MCHBAR16(0xfc4);
3148 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003149
3150 if (info->revision >= 8)
3151 read_4090(info);
3152
3153 if (!try_cached_training(info))
3154 do_ram_training(info);
3155 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3156 && info->clock_speed_index < 2)
3157 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003158 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003159}
3160
Martin Roth468d02c2019-10-23 21:44:42 -06003161static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003162{
Martin Roth468d02c2019-10-23 21:44:42 -06003163 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003164 if (a > b) {
3165 t = a;
3166 a = b;
3167 b = t;
3168 }
3169 /* invariant a < b. */
3170 while (a) {
3171 t = b % a;
3172 b = a;
3173 a = t;
3174 }
3175 return b;
3176}
3177
3178static inline int div_roundup(int a, int b)
3179{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003180 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003181}
3182
Martin Roth468d02c2019-10-23 21:44:42 -06003183static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003184{
3185 return (a * b) / gcd(a, b);
3186}
3187
3188struct stru1 {
3189 u8 freqs_reversed;
3190 u8 freq_diff_reduced;
3191 u8 freq_min_reduced;
3192 u8 divisor_f4_to_fmax;
3193 u8 divisor_f3_to_fmax;
3194 u8 freq4_to_max_remainder;
3195 u8 freq3_to_2_remainder;
3196 u8 freq3_to_2_remaindera;
3197 u8 freq4_to_2_remainder;
3198 int divisor_f3_to_f1, divisor_f4_to_f2;
3199 int common_time_unit_ps;
3200 int freq_max_reduced;
3201};
3202
3203static void
3204compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3205 int num_cycles_2, int num_cycles_1, int round_it,
3206 int add_freqs, struct stru1 *result)
3207{
3208 int g;
3209 int common_time_unit_ps;
3210 int freq1_reduced, freq2_reduced;
3211 int freq_min_reduced;
3212 int freq_max_reduced;
3213 int freq3, freq4;
3214
3215 g = gcd(freq1, freq2);
3216 freq1_reduced = freq1 / g;
3217 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003218 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3219 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003220
3221 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3222 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3223 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3224 if (add_freqs) {
3225 freq3 += freq2_reduced;
3226 freq4 += freq1_reduced;
3227 }
3228
3229 if (round_it) {
3230 result->freq3_to_2_remainder = 0;
3231 result->freq3_to_2_remaindera = 0;
3232 result->freq4_to_max_remainder = 0;
3233 result->divisor_f4_to_f2 = 0;
3234 result->divisor_f3_to_f1 = 0;
3235 } else {
3236 if (freq2_reduced < freq1_reduced) {
3237 result->freq3_to_2_remainder =
3238 result->freq3_to_2_remaindera =
3239 freq3 % freq1_reduced - freq1_reduced + 1;
3240 result->freq4_to_max_remainder =
3241 -(freq4 % freq1_reduced);
3242 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3243 result->divisor_f4_to_f2 =
3244 (freq4 -
3245 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3246 result->freq4_to_2_remainder =
3247 -(char)((freq1_reduced - freq2_reduced) +
3248 ((u8) freq4 -
3249 (freq1_reduced -
3250 freq2_reduced)) % (u8) freq2_reduced);
3251 } else {
3252 if (freq2_reduced > freq1_reduced) {
3253 result->freq4_to_max_remainder =
3254 (freq4 % freq2_reduced) - freq2_reduced + 1;
3255 result->freq4_to_2_remainder =
3256 freq4 % freq_max_reduced -
3257 freq_max_reduced + 1;
3258 } else {
3259 result->freq4_to_max_remainder =
3260 -(freq4 % freq2_reduced);
3261 result->freq4_to_2_remainder =
3262 -(char)(freq4 % freq_max_reduced);
3263 }
3264 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3265 result->divisor_f3_to_f1 =
3266 (freq3 -
3267 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3268 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3269 result->freq3_to_2_remaindera =
3270 -(char)((freq_max_reduced - freq_min_reduced) +
3271 (freq3 -
3272 (freq_max_reduced -
3273 freq_min_reduced)) % freq1_reduced);
3274 }
3275 }
3276 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3277 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3278 if (round_it) {
3279 if (freq2_reduced > freq1_reduced) {
3280 if (freq3 % freq_max_reduced)
3281 result->divisor_f3_to_fmax++;
3282 }
3283 if (freq2_reduced < freq1_reduced) {
3284 if (freq4 % freq_max_reduced)
3285 result->divisor_f4_to_fmax++;
3286 }
3287 }
3288 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3289 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3290 result->freq_min_reduced = freq_min_reduced;
3291 result->common_time_unit_ps = common_time_unit_ps;
3292 result->freq_max_reduced = freq_max_reduced;
3293}
3294
3295static void
3296set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3297 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3298 int num_cycles_4, int reverse)
3299{
3300 struct stru1 vv;
3301 char multiplier;
3302
3303 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3304 0, 1, &vv);
3305
3306 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003307 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003308 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3309 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3310 div_roundup(num_cycles_1,
3311 vv.common_time_unit_ps) +
3312 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3313 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3314
3315 u32 y =
3316 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3317 vv.freq_max_reduced * multiplier)
3318 | (vv.
3319 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3320 multiplier) << 16) | ((u8) (vv.
3321 freq_min_reduced
3322 *
3323 multiplier)
3324 << 24);
3325 u32 x =
3326 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3327 divisor_f3_to_f1
3328 << 16)
3329 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3330 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003331 MCHBAR32(reg) = y;
3332 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003333 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003334 MCHBAR32(reg + 4) = y;
3335 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003336 }
3337}
3338
3339static void
3340set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3341 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3342 int num_cycles_4)
3343{
3344 struct stru1 ratios1;
3345 struct stru1 ratios2;
3346
3347 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3348 0, 1, &ratios2);
3349 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3350 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003351 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003352 ratios1.freq4_to_max_remainder | (ratios2.
3353 freq4_to_max_remainder
3354 << 8)
3355 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3356 divisor_f4_to_fmax
3357 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003358 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3359 (ratios2.freq4_to_max_remainder << 8) |
3360 (ratios1.divisor_f4_to_fmax << 16) |
3361 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003362}
3363
3364static void
3365set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3366 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3367{
3368 struct stru1 ratios;
3369
3370 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3371 round_it, add_freqs, &ratios);
3372 switch (mode) {
3373 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003374 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3375 (ratios.freqs_reversed << 8);
3376 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3377 (ratios.freq4_to_max_remainder << 8) |
3378 (ratios.divisor_f3_to_fmax << 16) |
3379 (ratios.divisor_f4_to_fmax << 20) |
3380 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003381 break;
3382
3383 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003384 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3385 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003386 break;
3387
3388 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003389 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3390 (ratios.freq4_to_max_remainder << 8) |
3391 (ratios.divisor_f3_to_fmax << 16) |
3392 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003393 break;
3394
3395 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003396 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3397 (ratios.divisor_f4_to_fmax << 8) |
3398 (ratios.freqs_reversed << 12) |
3399 (ratios.freq_min_reduced << 16) |
3400 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003401 break;
3402 }
3403}
3404
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003405static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406{
3407 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3408 0, 1);
3409 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3410 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3411 1);
3412 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3413 frequency_11(info), 1231, 1524, 0, 1);
3414 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3415 frequency_11(info) / 2, 1278, 2008, 0, 1);
3416 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3417 1167, 1539, 0, 1);
3418 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3419 frequency_11(info) / 2, 1403, 1318, 0, 1);
3420 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3421 1);
3422 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3423 1);
3424 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3425 1, 1);
3426 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3427 1);
3428 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3429 frequency_11(info) / 2, 4000, 0, 0, 0);
3430 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3431 frequency_11(info) / 2, 4000, 4000, 0, 0);
3432
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003433 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003434 printk(RAM_SPEW, "[6dc] <= %x\n",
3435 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003436 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003437 } else
3438 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3439 info->delay46_ps[0], 0,
3440 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003441 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3442 frequency_11(info), 2500, 0, 0, 0);
3443 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3444 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003445 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003446 printk(RAM_SPEW, "[6e8] <= %x\n",
3447 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003448 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003449 } else
3450 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3451 info->delay46_ps[1], 0,
3452 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003453 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3454 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3455 470, 0);
3456 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3457 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3458 454, 459, 0);
3459 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3460 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3461 2588, 0);
3462 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3463 2405, 0);
3464 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3465 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3466 480, 0);
3467 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003468 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3469 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003470}
3471
3472static u16 get_max_timing(struct raminfo *info, int channel)
3473{
3474 int slot, rank, lane;
3475 u16 ret = 0;
3476
Felix Held04be2dd2018-07-29 04:53:22 +02003477 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003478 return 384;
3479
3480 if (info->revision < 8)
3481 return 256;
3482
3483 for (slot = 0; slot < NUM_SLOTS; slot++)
3484 for (rank = 0; rank < NUM_RANKS; rank++)
3485 if (info->populated_ranks[channel][slot][rank])
3486 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003487 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488 get_timing_register_addr
3489 (lane, 0, slot,
3490 rank), 9));
3491 return ret;
3492}
3493
3494static void set_274265(struct raminfo *info)
3495{
3496 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3497 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3498 int delay_e_over_cycle_ps;
3499 int cycletime_ps;
3500 int channel;
3501
3502 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003503 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3505 cycletime_ps =
3506 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3507 delay_d_ps =
3508 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3509 - info->some_delay_3_ps_rounded + 200;
3510 if (!
3511 ((info->silicon_revision == 0
3512 || info->silicon_revision == 1)
3513 && (info->revision >= 8)))
3514 delay_d_ps += halfcycle_ps(info) * 2;
3515 delay_d_ps +=
3516 halfcycle_ps(info) * (!info->revision_flag_1 +
3517 info->some_delay_2_halfcycles_ceil +
3518 2 * info->some_delay_1_cycle_floor +
3519 info->clock_speed_index +
3520 2 * info->cas_latency - 7 + 11);
3521 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3522
Felix Held04be2dd2018-07-29 04:53:22 +02003523 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3524 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3525 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003526 delay_d_ps += 650;
3527 delay_c_ps = delay_d_ps + 1800;
3528 if (delay_c_ps <= delay_a_ps)
3529 delay_e_ps = 0;
3530 else
3531 delay_e_ps =
3532 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3533 cycletime_ps);
3534
3535 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3536 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3537 delay_f_cycles =
3538 div_roundup(2500 - delay_e_over_cycle_ps,
3539 2 * halfcycle_ps(info));
3540 if (delay_f_cycles > delay_e_cycles) {
3541 info->delay46_ps[channel] = delay_e_ps;
3542 delay_e_cycles = 0;
3543 } else {
3544 info->delay46_ps[channel] =
3545 delay_e_over_cycle_ps +
3546 2 * halfcycle_ps(info) * delay_f_cycles;
3547 delay_e_cycles -= delay_f_cycles;
3548 }
3549
3550 if (info->delay46_ps[channel] < 2500) {
3551 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003552 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003553 }
3554 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3555 if (delay_b_ps <= delay_a_ps)
3556 delay_b_ps = 0;
3557 else
3558 delay_b_ps -= delay_a_ps;
3559 info->delay54_ps[channel] =
3560 cycletime_ps * div_roundup(delay_b_ps,
3561 cycletime_ps) -
3562 2 * halfcycle_ps(info) * delay_e_cycles;
3563 if (info->delay54_ps[channel] < 2500)
3564 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003565 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003566 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3567 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003568 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003569 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003570 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003571 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3572 4 * halfcycle_ps(info)) - 6;
3573 MCHBAR32((channel << 10) + 0x274) =
3574 info->training.reg274265[channel][1] |
3575 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003576 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003577 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3578 4 * halfcycle_ps(info)) + 1;
3579 MCHBAR16((channel << 10) + 0x265) =
3580 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003581 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003582 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003583 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003584 else
Felix Held04be2dd2018-07-29 04:53:22 +02003585 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003586}
3587
3588static void restore_274265(struct raminfo *info)
3589{
3590 int channel;
3591
3592 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003593 MCHBAR32((channel << 10) + 0x274) =
3594 (info->cached_training->reg274265[channel][0] << 16) |
3595 info->cached_training->reg274265[channel][1];
3596 MCHBAR16((channel << 10) + 0x265) =
3597 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003599 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003600 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003601 else
Felix Held04be2dd2018-07-29 04:53:22 +02003602 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603}
3604
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605static void dmi_setup(void)
3606{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003607 gav(DMIBAR8(0x254));
3608 DMIBAR8(0x254) = 0x1;
3609 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003610 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611
Angel Ponsd071c4d2020-09-14 23:51:35 +02003612 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613
3614 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3615 DEFAULT_GPIOBASE | 0x38);
3616 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3617}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003619void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003622 u16 ggc;
3623 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624
Felix Held04be2dd2018-07-29 04:53:22 +02003625 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3627 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003628 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003629 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631
3632 dmi_setup();
3633
Felix Held04be2dd2018-07-29 04:53:22 +02003634 MCHBAR16(0x1170) = 0xa880;
3635 MCHBAR8(0x11c1) = 0x1;
3636 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003637 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003639 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3640 /* 0 for 32MB */
3641 gfxsize = 0;
3642 }
3643
3644 ggc = 0xb00 | ((gfxsize + 5) << 4);
3645
Angel Pons16fe1e02020-07-22 16:12:33 +02003646 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647
3648 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003649 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
3651 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003652 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003653 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003654 MCHBAR16_OR(0x2c30, 0x200);
3655 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003656 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003657 pci_read_config8(GMA, MSAC); // = 0x2
3658 pci_write_config8(GMA, MSAC, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003659 read8(DEFAULT_RCBA + 0x2318);
3660 write8(DEFAULT_RCBA + 0x2318, 0x47);
3661 read8(DEFAULT_RCBA + 0x2320);
3662 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663 }
3664
Felix Heldf83d80b2018-07-29 05:30:30 +02003665 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666
Angel Pons16fe1e02020-07-22 16:12:33 +02003667 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003668 gav(read32(DEFAULT_RCBA + 0x3428));
3669 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003670}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003672void raminit(const int s3resume, const u8 *spd_addrmap)
3673{
Martin Roth468d02c2019-10-23 21:44:42 -06003674 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003675 int i;
3676 struct raminfo info;
3677 u8 x2ca8;
3678 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003679 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003680
Felix Held04be2dd2018-07-29 04:53:22 +02003681 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003682
3683 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3684
Angel Pons16fe1e02020-07-22 16:12:33 +02003685 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686
3687 memset(&info, 0x5a, sizeof(info));
3688
3689 info.last_500_command[0] = 0;
3690 info.last_500_command[1] = 0;
3691
3692 info.fsb_frequency = 135 * 2;
3693 info.board_lane_delay[0] = 0x14;
3694 info.board_lane_delay[1] = 0x07;
3695 info.board_lane_delay[2] = 0x07;
3696 info.board_lane_delay[3] = 0x08;
3697 info.board_lane_delay[4] = 0x56;
3698 info.board_lane_delay[5] = 0x04;
3699 info.board_lane_delay[6] = 0x04;
3700 info.board_lane_delay[7] = 0x05;
3701 info.board_lane_delay[8] = 0x10;
3702
3703 info.training.reg_178 = 0;
3704 info.training.reg_10b = 0;
3705
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706 info.memory_reserved_for_heci_mb = 0;
3707
3708 /* before SPD */
3709 timestamp_add_now(101);
3710
Felix Held29a9c072018-07-29 01:34:45 +02003711 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003712 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713
3714 collect_system_info(&info);
3715
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003716 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3717
3718 info.use_ecc = 1;
3719 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003720 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003721 int v;
3722 int try;
3723 int addr;
3724 const u8 useful_addresses[] = {
3725 DEVICE_TYPE,
3726 MODULE_TYPE,
3727 DENSITY,
3728 RANKS_AND_DQ,
3729 MEMORY_BUS_WIDTH,
3730 TIMEBASE_DIVIDEND,
3731 TIMEBASE_DIVISOR,
3732 CYCLETIME,
3733 CAS_LATENCIES_LSB,
3734 CAS_LATENCIES_MSB,
3735 CAS_LATENCY_TIME,
3736 0x11, 0x12, 0x13, 0x14, 0x15,
3737 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3738 0x1c, 0x1d,
3739 THERMAL_AND_REFRESH,
3740 0x20,
3741 REFERENCE_RAW_CARD_USED,
3742 RANK1_ADDRESS_MAPPING,
3743 0x75, 0x76, 0x77, 0x78,
3744 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3745 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3746 0x85, 0x86, 0x87, 0x88,
3747 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3748 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3749 0x95
3750 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003751 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003752 continue;
3753 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003754 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003755 DEVICE_TYPE);
3756 if (v >= 0)
3757 break;
3758 }
3759 if (v < 0)
3760 continue;
3761 for (addr = 0;
3762 addr <
3763 sizeof(useful_addresses) /
3764 sizeof(useful_addresses[0]); addr++)
3765 gav(info.
3766 spd[channel][0][useful_addresses
3767 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003768 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003769 useful_addresses
3770 [addr]));
3771 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3772 die("Only DDR3 is supported");
3773
3774 v = info.spd[channel][0][RANKS_AND_DQ];
3775 info.populated_ranks[channel][0][0] = 1;
3776 info.populated_ranks[channel][0][1] =
3777 ((v >> 3) & 7);
3778 if (((v >> 3) & 7) > 1)
3779 die("At most 2 ranks are supported");
3780 if ((v & 7) == 0 || (v & 7) > 2)
3781 die("Only x8 and x16 modules are supported");
3782 if ((info.
3783 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3784 && (info.
3785 spd[channel][slot][MODULE_TYPE] & 0xF)
3786 != 3)
3787 die("Registered memory is not supported");
3788 info.is_x16_module[channel][0] = (v & 7) - 1;
3789 info.density[channel][slot] =
3790 info.spd[channel][slot][DENSITY] & 0xF;
3791 if (!
3792 (info.
3793 spd[channel][slot][MEMORY_BUS_WIDTH] &
3794 0x18))
3795 info.use_ecc = 0;
3796 }
3797
3798 gav(0x55);
3799
3800 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3801 int v = 0;
3802 for (slot = 0; slot < NUM_SLOTS; slot++)
3803 for (rank = 0; rank < NUM_RANKS; rank++)
3804 v |= info.
3805 populated_ranks[channel][slot][rank]
3806 << (2 * slot + rank);
3807 info.populated_ranks_mask[channel] = v;
3808 }
3809
3810 gav(0x55);
3811
Angel Pons16fe1e02020-07-22 16:12:33 +02003812 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003813 }
3814
3815 /* after SPD */
3816 timestamp_add_now(102);
3817
Felix Held04be2dd2018-07-29 04:53:22 +02003818 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819
3820 collect_system_info(&info);
3821 calculate_timings(&info);
3822
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003823 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003824 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003825 if (x2ca8 == 0 && (reg8 & 0x80)) {
3826 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3827 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3828 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3829 */
3830
3831 /* Clear bit7. */
3832
3833 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3834 (reg8 & ~(1 << 7)));
3835
3836 printk(BIOS_INFO,
3837 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003838 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003839 }
3840 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003841
3842 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003843 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3844 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003845
3846 compute_derived_timings(&info);
3847
3848 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003849 gav(MCHBAR8(0x164));
3850 MCHBAR8(0x164) = 0x26;
3851 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003852 }
3853
Felix Held04be2dd2018-07-29 04:53:22 +02003854 MCHBAR32_OR(0x18b4, 0x210000);
3855 MCHBAR32_OR(0x1890, 0x2000000);
3856 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003857
Angel Ponsa457e352020-07-22 18:17:33 +02003858 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3859 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003860
Felix Held04be2dd2018-07-29 04:53:22 +02003861 gav(MCHBAR16(0x2c10));
3862 MCHBAR16(0x2c10) = 0x412;
3863 gav(MCHBAR16(0x2c10));
3864 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003865
Felix Held04be2dd2018-07-29 04:53:22 +02003866 gav(MCHBAR8(0x2ca8)); // !!!!
3867 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868
Angel Ponsa457e352020-07-22 18:17:33 +02003869 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3870 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003871 gav(MCHBAR32(0x1c04)); // !!!!
3872 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003873
3874 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003875 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876 }
3877
Felix Held04be2dd2018-07-29 04:53:22 +02003878 MCHBAR32(0x18d8) = 0x120000;
3879 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003880 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3881 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003882 MCHBAR32(0x18d8) = 0x40000;
3883 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003884 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3885 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003886 MCHBAR32(0x18d8) = 0x180000;
3887 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003888 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3889 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003890 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003891
Felix Held04be2dd2018-07-29 04:53:22 +02003892 gav(MCHBAR32(0x18dc)); // !!!!
3893 MCHBAR32(0x18dc) = 0x3;
3894 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895
3896 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003898 }
3899
Felix Held04be2dd2018-07-29 04:53:22 +02003900 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003901 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003902 MCHBAR32(0x1a10) = 0x4200010e;
3903 MCHBAR32_OR(0x18b8, 0x200);
3904 gav(MCHBAR32(0x1918)); // !!!!
3905 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906
Felix Held04be2dd2018-07-29 04:53:22 +02003907 gav(MCHBAR32(0x18b8)); // !!!!
3908 MCHBAR32(0x18b8) = 0xe00;
3909 gav(MCHBAR32(0x182c)); // !!!!
3910 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003911 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3912 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003913 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3914 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003915
Felix Held04be2dd2018-07-29 04:53:22 +02003916 MCHBAR32_AND(0x18b4, 0xffff7fff);
3917 gav(MCHBAR32(0x1a68)); // !!!!
3918 MCHBAR32(0x1a68) = 0x343800;
3919 gav(MCHBAR32(0x1e68)); // !!!!
3920 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921
3922 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003923 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003924 }
3925
Angel Pons08143572020-07-22 17:47:06 +02003926 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3927 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3928 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3929 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3930 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003931 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3932 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003933 gav(MCHBAR32(0x1af0)); // !!!!
3934 gav(MCHBAR32(0x1af0)); // !!!!
3935 MCHBAR32(0x1af0) = 0x1f020003;
3936 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003937
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003938 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003939 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003940 }
3941
Felix Held04be2dd2018-07-29 04:53:22 +02003942 gav(MCHBAR32(0x1890)); // !!!!
3943 MCHBAR32(0x1890) = 0x80102;
3944 gav(MCHBAR32(0x18b4)); // !!!!
3945 MCHBAR32(0x18b4) = 0x216000;
3946 MCHBAR32(0x18a4) = 0x22222222;
3947 MCHBAR32(0x18a8) = 0x22222222;
3948 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003949
3950 udelay(1000);
3951
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003952 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003953
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003954 if (x2ca8 == 0) {
3955 int j;
3956 if (s3resume && info.cached_training) {
3957 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003958 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003959 info.cached_training->reg2ca9_bit0);
3960 for (i = 0; i < 2; i++)
3961 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003962 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003963 i, j, info.cached_training->reg274265[i][j]);
3964 } else {
3965 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003966 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003967 info.training.reg2ca9_bit0);
3968 for (i = 0; i < 2; i++)
3969 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003970 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003971 i, j, info.training.reg274265[i][j]);
3972 }
3973
3974 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975
3976 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003977 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003978 }
3979
3980 udelay(1000);
3981
3982 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003983 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003984 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003985 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3986 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3987 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003988
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003989 MCHBAR8(0x1150);
3990 MCHBAR8(0x1151);
3991 MCHBAR8(0x1022);
3992 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02003993 MCHBAR32(0x1300) = 0x60606060;
3994 MCHBAR32(0x1304) = 0x60606060;
3995 MCHBAR32(0x1308) = 0x78797a7b;
3996 MCHBAR32(0x130c) = 0x7c7d7e7f;
3997 MCHBAR32(0x1310) = 0x60606060;
3998 MCHBAR32(0x1314) = 0x60606060;
3999 MCHBAR32(0x1318) = 0x60606060;
4000 MCHBAR32(0x131c) = 0x60606060;
4001 MCHBAR32(0x1320) = 0x50515253;
4002 MCHBAR32(0x1324) = 0x54555657;
4003 MCHBAR32(0x1328) = 0x58595a5b;
4004 MCHBAR32(0x132c) = 0x5c5d5e5f;
4005 MCHBAR32(0x1330) = 0x40414243;
4006 MCHBAR32(0x1334) = 0x44454647;
4007 MCHBAR32(0x1338) = 0x48494a4b;
4008 MCHBAR32(0x133c) = 0x4c4d4e4f;
4009 MCHBAR32(0x1340) = 0x30313233;
4010 MCHBAR32(0x1344) = 0x34353637;
4011 MCHBAR32(0x1348) = 0x38393a3b;
4012 MCHBAR32(0x134c) = 0x3c3d3e3f;
4013 MCHBAR32(0x1350) = 0x20212223;
4014 MCHBAR32(0x1354) = 0x24252627;
4015 MCHBAR32(0x1358) = 0x28292a2b;
4016 MCHBAR32(0x135c) = 0x2c2d2e2f;
4017 MCHBAR32(0x1360) = 0x10111213;
4018 MCHBAR32(0x1364) = 0x14151617;
4019 MCHBAR32(0x1368) = 0x18191a1b;
4020 MCHBAR32(0x136c) = 0x1c1d1e1f;
4021 MCHBAR32(0x1370) = 0x10203;
4022 MCHBAR32(0x1374) = 0x4050607;
4023 MCHBAR32(0x1378) = 0x8090a0b;
4024 MCHBAR32(0x137c) = 0xc0d0e0f;
4025 MCHBAR8(0x11cc) = 0x4e;
4026 MCHBAR32(0x1110) = 0x73970404;
4027 MCHBAR32(0x1114) = 0x72960404;
4028 MCHBAR32(0x1118) = 0x6f950404;
4029 MCHBAR32(0x111c) = 0x6d940404;
4030 MCHBAR32(0x1120) = 0x6a930404;
4031 MCHBAR32(0x1124) = 0x68a41404;
4032 MCHBAR32(0x1128) = 0x66a21404;
4033 MCHBAR32(0x112c) = 0x63a01404;
4034 MCHBAR32(0x1130) = 0x609e1404;
4035 MCHBAR32(0x1134) = 0x5f9c1404;
4036 MCHBAR32(0x1138) = 0x5c961404;
4037 MCHBAR32(0x113c) = 0x58a02404;
4038 MCHBAR32(0x1140) = 0x54942404;
4039 MCHBAR32(0x1190) = 0x900080a;
4040 MCHBAR16(0x11c0) = 0xc40b;
4041 MCHBAR16(0x11c2) = 0x303;
4042 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004043 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004044 MCHBAR32(0x11b8) = 0x70c3000;
4045 MCHBAR8(0x11ec) = 0xa;
4046 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004047 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004048 MCHBAR16(0x11ca) = 0xfa;
4049 MCHBAR32(0x11e4) = 0x4e20;
4050 MCHBAR8(0x11bc) = 0xf;
4051 MCHBAR16(0x11da) = 0x19;
4052 MCHBAR16(0x11ba) = 0x470c;
4053 MCHBAR32(0x1680) = 0xe6ffe4ff;
4054 MCHBAR32(0x1684) = 0xdeffdaff;
4055 MCHBAR32(0x1688) = 0xd4ffd0ff;
4056 MCHBAR32(0x168c) = 0xccffc6ff;
4057 MCHBAR32(0x1690) = 0xc0ffbeff;
4058 MCHBAR32(0x1694) = 0xb8ffb0ff;
4059 MCHBAR32(0x1698) = 0xa8ff0000;
4060 MCHBAR32(0x169c) = 0xc00;
4061 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004062 }
4063
Felix Held04be2dd2018-07-29 04:53:22 +02004064 MCHBAR32(0x124c) = 0x15040d00;
4065 MCHBAR32(0x1250) = 0x7f0000;
4066 MCHBAR32(0x1254) = 0x1e220004;
4067 MCHBAR32(0x1258) = 0x4000004;
4068 MCHBAR32(0x1278) = 0x0;
4069 MCHBAR32(0x125c) = 0x0;
4070 MCHBAR32(0x1260) = 0x0;
4071 MCHBAR32(0x1264) = 0x0;
4072 MCHBAR32(0x1268) = 0x0;
4073 MCHBAR32(0x126c) = 0x0;
4074 MCHBAR32(0x1270) = 0x0;
4075 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004076 }
4077
4078 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004079 MCHBAR16(0x1214) = 0x320;
4080 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004081 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4082 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004083 MCHBAR32(0x1400) = 0x13040020;
4084 MCHBAR32(0x1404) = 0xe090120;
4085 MCHBAR32(0x1408) = 0x5120220;
4086 MCHBAR32(0x140c) = 0x5120330;
4087 MCHBAR32(0x1410) = 0xe090220;
4088 MCHBAR32(0x1414) = 0x1010001;
4089 MCHBAR32(0x1418) = 0x1110000;
4090 MCHBAR32(0x141c) = 0x9020020;
4091 MCHBAR32(0x1420) = 0xd090220;
4092 MCHBAR32(0x1424) = 0x2090220;
4093 MCHBAR32(0x1428) = 0x2090330;
4094 MCHBAR32(0x142c) = 0xd090220;
4095 MCHBAR32(0x1430) = 0x1010001;
4096 MCHBAR32(0x1434) = 0x1110000;
4097 MCHBAR32(0x1438) = 0x11040020;
4098 MCHBAR32(0x143c) = 0x4030220;
4099 MCHBAR32(0x1440) = 0x1060220;
4100 MCHBAR32(0x1444) = 0x1060330;
4101 MCHBAR32(0x1448) = 0x4030220;
4102 MCHBAR32(0x144c) = 0x1010001;
4103 MCHBAR32(0x1450) = 0x1110000;
4104 MCHBAR32(0x1454) = 0x4010020;
4105 MCHBAR32(0x1458) = 0xb090220;
4106 MCHBAR32(0x145c) = 0x1090220;
4107 MCHBAR32(0x1460) = 0x1090330;
4108 MCHBAR32(0x1464) = 0xb090220;
4109 MCHBAR32(0x1468) = 0x1010001;
4110 MCHBAR32(0x146c) = 0x1110000;
4111 MCHBAR32(0x1470) = 0xf040020;
4112 MCHBAR32(0x1474) = 0xa090220;
4113 MCHBAR32(0x1478) = 0x1120220;
4114 MCHBAR32(0x147c) = 0x1120330;
4115 MCHBAR32(0x1480) = 0xa090220;
4116 MCHBAR32(0x1484) = 0x1010001;
4117 MCHBAR32(0x1488) = 0x1110000;
4118 MCHBAR32(0x148c) = 0x7020020;
4119 MCHBAR32(0x1490) = 0x1010220;
4120 MCHBAR32(0x1494) = 0x10210;
4121 MCHBAR32(0x1498) = 0x10320;
4122 MCHBAR32(0x149c) = 0x1010220;
4123 MCHBAR32(0x14a0) = 0x1010001;
4124 MCHBAR32(0x14a4) = 0x1110000;
4125 MCHBAR32(0x14a8) = 0xd040020;
4126 MCHBAR32(0x14ac) = 0x8090220;
4127 MCHBAR32(0x14b0) = 0x1111310;
4128 MCHBAR32(0x14b4) = 0x1111420;
4129 MCHBAR32(0x14b8) = 0x8090220;
4130 MCHBAR32(0x14bc) = 0x1010001;
4131 MCHBAR32(0x14c0) = 0x1110000;
4132 MCHBAR32(0x14c4) = 0x3010020;
4133 MCHBAR32(0x14c8) = 0x7090220;
4134 MCHBAR32(0x14cc) = 0x1081310;
4135 MCHBAR32(0x14d0) = 0x1081420;
4136 MCHBAR32(0x14d4) = 0x7090220;
4137 MCHBAR32(0x14d8) = 0x1010001;
4138 MCHBAR32(0x14dc) = 0x1110000;
4139 MCHBAR32(0x14e0) = 0xb040020;
4140 MCHBAR32(0x14e4) = 0x2030220;
4141 MCHBAR32(0x14e8) = 0x1051310;
4142 MCHBAR32(0x14ec) = 0x1051420;
4143 MCHBAR32(0x14f0) = 0x2030220;
4144 MCHBAR32(0x14f4) = 0x1010001;
4145 MCHBAR32(0x14f8) = 0x1110000;
4146 MCHBAR32(0x14fc) = 0x5020020;
4147 MCHBAR32(0x1500) = 0x5090220;
4148 MCHBAR32(0x1504) = 0x2071310;
4149 MCHBAR32(0x1508) = 0x2071420;
4150 MCHBAR32(0x150c) = 0x5090220;
4151 MCHBAR32(0x1510) = 0x1010001;
4152 MCHBAR32(0x1514) = 0x1110000;
4153 MCHBAR32(0x1518) = 0x7040120;
4154 MCHBAR32(0x151c) = 0x2090220;
4155 MCHBAR32(0x1520) = 0x70b1210;
4156 MCHBAR32(0x1524) = 0x70b1310;
4157 MCHBAR32(0x1528) = 0x2090220;
4158 MCHBAR32(0x152c) = 0x1010001;
4159 MCHBAR32(0x1530) = 0x1110000;
4160 MCHBAR32(0x1534) = 0x1010110;
4161 MCHBAR32(0x1538) = 0x1081310;
4162 MCHBAR32(0x153c) = 0x5041200;
4163 MCHBAR32(0x1540) = 0x5041310;
4164 MCHBAR32(0x1544) = 0x1081310;
4165 MCHBAR32(0x1548) = 0x1010001;
4166 MCHBAR32(0x154c) = 0x1110000;
4167 MCHBAR32(0x1550) = 0x1040120;
4168 MCHBAR32(0x1554) = 0x4051210;
4169 MCHBAR32(0x1558) = 0xd051200;
4170 MCHBAR32(0x155c) = 0xd051200;
4171 MCHBAR32(0x1560) = 0x4051210;
4172 MCHBAR32(0x1564) = 0x1010001;
4173 MCHBAR32(0x1568) = 0x1110000;
4174 MCHBAR16(0x1222) = 0x220a;
4175 MCHBAR16(0x123c) = 0x1fc0;
4176 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004177 }
4178
Felix Heldf83d80b2018-07-29 05:30:30 +02004179 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004180 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004181 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004182
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004183 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004184
4185 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004186 MCHBAR8_AND(0x2ca8, ~3);
4187 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004188 /* This issues a CPU reset without resetting the platform */
4189 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004190 /* Write back the S3 state to PM1_CNT to let the reset CPU
4191 know it also needs to take the s3 path. */
4192 if (s3resume)
4193 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4194 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004195 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004196 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004197 }
4198
Felix Held04be2dd2018-07-29 04:53:22 +02004199 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004200 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004201 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004202 MCHBAR16(0x2c20); // !!!!
4203 MCHBAR16(0x2c10); // !!!!
4204 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004205 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004206 udelay(1000);
4207 write_1d0(0, 0x33d, 0, 0);
4208 write_500(&info, 0, 0, 0xb61, 0, 0);
4209 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004210 MCHBAR32(0x1a30) = 0x0;
4211 MCHBAR32(0x1a34) = 0x0;
4212 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4213 (info.populated_ranks[0][0][0] * 0xa0);
4214 MCHBAR16(0x616) = 0x26a;
4215 MCHBAR32(0x134) = 0x856000;
4216 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004217 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4218 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004219 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004220 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4221 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004222 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004223 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004224 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4225 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004226 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4227 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4228 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4229 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4230 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4231 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4232 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4233 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4234 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4235 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236 }
4237
4238 write_1d0(0x4, 0x151, 4, 1);
4239 write_1d0(0, 0x142, 3, 1);
4240 rdmsr(0x1ac); // !!!!
4241 write_500(&info, 1, 1, 0x6b3, 4, 1);
4242 write_500(&info, 1, 1, 0x6cf, 4, 1);
4243
4244 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4245
4246 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4247 populated_ranks[0]
4248 [0][0]) << 0),
4249 0x1d1, 3, 1);
4250 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004251 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4252 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253 }
4254
4255 set_334(0);
4256
4257 program_base_timings(&info);
4258
Felix Held04be2dd2018-07-29 04:53:22 +02004259 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004260
4261 write_1d0(0x2, 0x1d5, 2, 1);
4262 write_1d0(0x20, 0x166, 7, 1);
4263 write_1d0(0x0, 0xeb, 3, 1);
4264 write_1d0(0x0, 0xf3, 6, 1);
4265
4266 for (channel = 0; channel < NUM_CHANNELS; channel++)
4267 for (lane = 0; lane < 9; lane++) {
4268 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4269 u8 a;
4270 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4271 write_500(&info, channel, a, addr, 6, 1);
4272 }
4273
4274 udelay(1000);
4275
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004276 if (s3resume) {
4277 if (info.cached_training == NULL) {
4278 u32 reg32;
4279 printk(BIOS_ERR,
4280 "Couldn't find training data. Rebooting\n");
4281 reg32 = inl(DEFAULT_PMBASE + 0x04);
4282 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004283 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004284 }
4285 int tm;
4286 info.training = *info.cached_training;
4287 for (tm = 0; tm < 4; tm++)
4288 for (channel = 0; channel < NUM_CHANNELS; channel++)
4289 for (slot = 0; slot < NUM_SLOTS; slot++)
4290 for (rank = 0; rank < NUM_RANKS; rank++)
4291 for (lane = 0; lane < 9; lane++)
4292 write_500(&info,
4293 channel,
4294 info.training.
4295 lane_timings
4296 [tm][channel]
4297 [slot][rank]
4298 [lane],
4299 get_timing_register_addr
4300 (lane, tm,
4301 slot, rank),
4302 9, 0);
4303 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4304 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4305 }
4306
Felix Heldf83d80b2018-07-29 05:30:30 +02004307 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004308 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004309 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004310 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004311
4312 program_board_delay(&info);
4313
Felix Held04be2dd2018-07-29 04:53:22 +02004314 MCHBAR8(0x5ff) = 0x0;
4315 MCHBAR8(0x5ff) = 0x80;
4316 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004317
Felix Held04be2dd2018-07-29 04:53:22 +02004318 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004319 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004320 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004321 gav(read_1d0(0x14b, 7)); // = 0x81023100
4322 write_1d0(0x30, 0x14b, 7, 1);
4323 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4324 write_1d0(7, 0xd6, 6, 1);
4325 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4326 write_1d0(7, 0x328, 6, 1);
4327
4328 for (channel = 0; channel < NUM_CHANNELS; channel++)
4329 set_4cf(&info, channel,
4330 info.populated_ranks[channel][0][0] ? 8 : 0);
4331
4332 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4333 write_1d0(2, 0x116, 4, 1);
4334 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4335 write_1d0(0, 0xae, 6, 1);
4336 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4337 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004338 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4339 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004340 MCHBAR32_AND(0x140, ~0x07000000);
4341 MCHBAR32_AND(0x138, ~0x07000000);
4342 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004343 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004344 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004345 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004346
4347 {
4348 u32 t;
4349 u8 val_a1;
4350 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4351 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4352 rmw_1d0(0x320, 0x07,
4353 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4354 rmw_1d0(0x14b, 0x78,
4355 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4356 4), 7,
4357 1);
4358 rmw_1d0(0xce, 0x38,
4359 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4360 4), 6,
4361 1);
4362 }
4363
4364 for (channel = 0; channel < NUM_CHANNELS; channel++)
4365 set_4cf(&info, channel,
4366 info.populated_ranks[channel][0][0] ? 9 : 1);
4367
4368 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004369 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004370 write_1d0(2, 0xae, 6, 1);
4371 write_1d0(2, 0x300, 6, 1);
4372 write_1d0(2, 0x121, 3, 1);
4373 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4374 write_1d0(4, 0xd6, 6, 1);
4375 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4376 write_1d0(4, 0x328, 6, 1);
4377
4378 for (channel = 0; channel < NUM_CHANNELS; channel++)
4379 set_4cf(&info, channel,
4380 info.populated_ranks[channel][0][0] ? 9 : 0);
4381
Felix Held04be2dd2018-07-29 04:53:22 +02004382 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4383 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004384 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004385 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004386 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4387 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4388 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4389 write_1d0(0, 0x21c, 6, 1);
4390 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4391 write_1d0(0x35, 0x14b, 7, 1);
4392
4393 for (channel = 0; channel < NUM_CHANNELS; channel++)
4394 set_4cf(&info, channel,
4395 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4396
4397 set_334(1);
4398
Felix Held04be2dd2018-07-29 04:53:22 +02004399 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004400
4401 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4402 write_500(&info, channel,
4403 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4404 1);
4405 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4406 }
Felix Held04be2dd2018-07-29 04:53:22 +02004407 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4408 MCHBAR16(0x6c0) = 0x14a0;
4409 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4410 MCHBAR16(0x232) = 0x8;
4411 /* 0x40004 or 0 depending on ? */
4412 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4413 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4414 MCHBAR32(0x128) = 0x2150d05;
4415 MCHBAR8(0x12c) = 0x1f;
4416 MCHBAR8(0x12d) = 0x56;
4417 MCHBAR8(0x12e) = 0x31;
4418 MCHBAR8(0x12f) = 0x0;
4419 MCHBAR8(0x271) = 0x2;
4420 MCHBAR8(0x671) = 0x2;
4421 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004422 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004423 MCHBAR32(0x294 + (channel << 10)) =
4424 (info.populated_ranks_mask[channel] & 3) << 16;
4425 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4426 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004427 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004428 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4429 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004430
4431 if (!s3resume)
4432 jedec_init(&info);
4433
4434 int totalrank = 0;
4435 for (channel = 0; channel < NUM_CHANNELS; channel++)
4436 for (slot = 0; slot < NUM_SLOTS; slot++)
4437 for (rank = 0; rank < NUM_RANKS; rank++)
4438 if (info.populated_ranks[channel][slot][rank]) {
4439 jedec_read(&info, channel, slot, rank,
4440 totalrank, 0xa, 0x400);
4441 totalrank++;
4442 }
4443
Felix Held04be2dd2018-07-29 04:53:22 +02004444 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004445
Felix Heldf83d80b2018-07-29 05:30:30 +02004446 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4447 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004448
4449 if (!s3resume) {
4450 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004451 MCHBAR32(0x294 + (channel << 10)) =
4452 (info.populated_ranks_mask[channel] & 3) << 16;
4453 MCHBAR16(0x298 + (channel << 10)) =
4454 info.populated_ranks[channel][0][0] |
4455 (info.populated_ranks[channel][0][1] << 5);
4456 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004458 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004459
4460 {
4461 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004462 a = MCHBAR8(0x243);
4463 b = MCHBAR8(0x643);
4464 MCHBAR8(0x243) = a | 2;
4465 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004466 }
4467
4468 write_1d0(7, 0x19b, 3, 1);
4469 write_1d0(7, 0x1c0, 3, 1);
4470 write_1d0(4, 0x1c6, 4, 1);
4471 write_1d0(4, 0x1cc, 4, 1);
4472 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4473 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004474 MCHBAR32(0x584) = 0xfffff;
4475 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476
4477 for (channel = 0; channel < NUM_CHANNELS; channel++)
4478 for (slot = 0; slot < NUM_SLOTS; slot++)
4479 for (rank = 0; rank < NUM_RANKS; rank++)
4480 if (info.
4481 populated_ranks[channel][slot]
4482 [rank])
4483 config_rank(&info, s3resume,
4484 channel, slot,
4485 rank);
4486
Felix Held04be2dd2018-07-29 04:53:22 +02004487 MCHBAR8(0x243) = 0x1;
4488 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004489 }
4490
4491 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004492 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493 write_26c(0, 0x820);
4494 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004495 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004496 /* end */
4497
4498 if (s3resume) {
4499 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004500 MCHBAR32(0x294 + (channel << 10)) =
4501 (info.populated_ranks_mask[channel] & 3) << 16;
4502 MCHBAR16(0x298 + (channel << 10)) =
4503 info.populated_ranks[channel][0][0] |
4504 (info.populated_ranks[channel][0][1] << 5);
4505 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004507 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508 }
4509
Felix Held04be2dd2018-07-29 04:53:22 +02004510 MCHBAR32_AND(0xfa4, ~0x01000002);
4511 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 /* Before training. */
4514 timestamp_add_now(103);
4515
4516 if (!s3resume)
4517 ram_training(&info);
4518
4519 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004520 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004521
4522 dump_timings(&info);
4523
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524 program_modules_memory_map(&info, 0);
4525 program_total_memory_map(&info);
4526
4527 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004528 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004530 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004532 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533 else
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535
Felix Held04be2dd2018-07-29 04:53:22 +02004536 MCHBAR32_AND(0xfac, ~0x80000000);
4537 MCHBAR32(0xfb4) = 0x4800;
4538 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4539 MCHBAR32(0xe94) = 0x7ffff;
4540 MCHBAR32(0xfc0) = 0x80002040;
4541 MCHBAR32(0xfc4) = 0x701246;
4542 MCHBAR8_AND(0xfc8, ~0x70);
4543 MCHBAR32_OR(0xe5c, 0x1000000);
4544 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4545 MCHBAR32(0x50) = 0x700b0;
4546 MCHBAR32(0x3c) = 0x10;
4547 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4548 MCHBAR8_OR(0xff4, 0x2);
4549 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550
Felix Held04be2dd2018-07-29 04:53:22 +02004551 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4552 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4553 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004555 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4556 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4557 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 {
4560 u32 eax;
4561
4562 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4564 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4565 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 }
4567
4568 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004569 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572 else
Felix Held04be2dd2018-07-29 04:53:22 +02004573 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576
Felix Held04be2dd2018-07-29 04:53:22 +02004577 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 else
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582 }
4583
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
4586 {
4587 u8 al;
4588 al = 0xd;
4589 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4590 al += 2;
4591 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 }
4594
4595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4597 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4598 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4599 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600 }
4601 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004602 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsd071c4d2020-09-14 23:51:35 +02004603 reg1c = EPBAR32(0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004604 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsd071c4d2020-09-14 23:51:35 +02004605 EPBAR32(0x01c) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004606 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004607 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004608 MCHBAR8_OR(0x1210, 2);
4609 MCHBAR32(0x1200) = 0x8800440;
4610 MCHBAR32(0x1204) = 0x53ff0453;
4611 MCHBAR32(0x1208) = 0x19002043;
4612 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004613
4614 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004615 MCHBAR16(0x1214) = 0x220;
4616 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004617 }
4618
Felix Held04be2dd2018-07-29 04:53:22 +02004619 MCHBAR8_OR(0x1214, 0x4);
4620 MCHBAR8(0x120c) = 0x1;
4621 MCHBAR8(0x1218) = 0x3;
4622 MCHBAR8(0x121a) = 0x3;
4623 MCHBAR8(0x121c) = 0x3;
4624 MCHBAR16(0xc14) = 0x0;
4625 MCHBAR16(0xc20) = 0x0;
4626 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627
4628 /* revision dependent here. */
4629
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631
4632 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR16_OR(0x1230, 0x8000);
4636 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637
4638 u8 bl, ebpb;
4639 u16 reg_1020;
4640
Felix Held04be2dd2018-07-29 04:53:22 +02004641 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4642 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32(0x1000) = 0x100;
4645 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
4647 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649 bl = reg_1020 >> 8;
4650 ebpb = reg_1020 & 0xff;
4651 } else {
4652 ebpb = 0;
4653 bl = 8;
4654 }
4655
4656 rdmsr(0x1a2);
4657
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
Felix Held04be2dd2018-07-29 04:53:22 +02004664 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004665 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004666 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4667 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004668 }
4669
4670 setup_heci_uma(&info);
4671
4672 if (info.uma_enabled) {
4673 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32_OR(0x11b0, 0x4000);
4675 MCHBAR32_OR(0x11b4, 0x4000);
4676 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677
Felix Held04be2dd2018-07-29 04:53:22 +02004678 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4679 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4680 MCHBAR16_OR(0x1170, 0x1000);
4681
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004683
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004685 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004686 ;
4687 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688 }
4689
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004690 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4691 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 udelay(1000);
4696 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004697 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4698
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 if (!s3resume)
4700 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004701 if (s3resume && cbmem_wasnot_inited) {
4702 u32 reg32;
4703 printk(BIOS_ERR, "Failed S3 resume.\n");
4704 ram_check(0x100000, 0x200000);
4705
4706 /* Clear SLP_TYPE. */
4707 reg32 = inl(DEFAULT_PMBASE + 0x04);
4708 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4709
4710 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004711 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004712 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713}