blob: 4d2e77a012b8e0f933609edbb2871b65d06d9ffe [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Angel Ponsd02f3302020-09-14 18:42:12 +020064#define MRC_CACHE_VERSION 2
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100104/* OK */
105static void write_1d0(u32 val, u16 addr, int bits, int flag)
106{
Felix Held04be2dd2018-07-29 04:53:22 +0200107 MCHBAR32(0x1d0) = 0;
108 while (MCHBAR32(0x1d0) & 0x800000)
109 ;
110 MCHBAR32(0x1d4) =
111 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
112 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200113 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200114 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100115}
116
117/* OK */
118static u16 read_1d0(u16 addr, int split)
119{
120 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200121 MCHBAR32(0x1d0) = 0;
122 while (MCHBAR32(0x1d0) & 0x800000)
123 ;
124 MCHBAR32(0x1d0) =
125 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
126 while (MCHBAR32(0x1d0) & 0x800000)
127 ;
128 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100129 write_1d0(0, 0x33d, 0, 0);
130 write_1d0(0, 0x33d, 0, 0);
131 val &= ((1 << split) - 1);
132 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
133 return val;
134}
135
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800136static void write32p(uintptr_t addr, uint32_t val)
137{
138 write32((void *)addr, val);
139}
140
141static uint32_t read32p(uintptr_t addr)
142{
143 return read32((void *)addr);
144}
145
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146static void sfence(void)
147{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100148 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100149}
150
151static inline u16 get_lane_offset(int slot, int rank, int lane)
152{
153 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
154 0x452 * (lane == 8);
155}
156
157static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
158{
159 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
160 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static u32 gav_real(int line, u32 in)
164{
165 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
166 return in;
167}
168
169#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200170
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100171struct raminfo {
172 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
173 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
174 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
175 u8 density[2][2]; /* [CHANNEL][SLOT] */
176 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
177 int rank_start[2][2][2];
178 u8 cas_latency;
179 u8 board_lane_delay[9];
180 u8 use_ecc;
181 u8 revision;
182 u8 max_supported_clock_speed_index;
183 u8 uma_enabled;
184 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
185 u8 silicon_revision;
186 u8 populated_ranks_mask[2];
187 u8 max_slots_used_in_channel;
188 u8 mode4030[2];
189 u16 avg4044[2];
190 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600191 unsigned int total_memory_mb;
192 unsigned int interleaved_part_mb;
193 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100194
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100195 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600196 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100197
198 struct ram_training training;
199 u32 last_500_command[2];
200
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100201 u32 delay46_ps[2];
202 u32 delay54_ps[2];
203 u8 revision_flag_1;
204 u8 some_delay_1_cycle_floor;
205 u8 some_delay_2_halfcycles_ceil;
206 u8 some_delay_3_ps_rounded;
207
208 const struct ram_training *cached_training;
209};
210
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200211/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100212timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200213
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214static void
215write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
216 int flag);
217
218/* OK */
219static u16
220read_500(struct raminfo *info, int channel, u16 addr, int split)
221{
222 u32 val;
223 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200224 MCHBAR32(0x500 + (channel << 10)) = 0;
225 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
226 ;
227 MCHBAR32(0x500 + (channel << 10)) =
228 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
229 + 0xb88 - addr);
230 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
231 ;
232 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100233 return val & ((1 << split) - 1);
234}
235
236/* OK */
237static void
238write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
239 int flag)
240{
241 if (info->last_500_command[channel] == 0x80000000) {
242 info->last_500_command[channel] = 0x40000000;
243 write_500(info, channel, 0, 0xb61, 0, 0);
244 }
Felix Held04be2dd2018-07-29 04:53:22 +0200245 MCHBAR32(0x500 + (channel << 10)) = 0;
246 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
247 ;
248 MCHBAR32(0x504 + (channel << 10)) =
249 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
250 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200251 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200252 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100253}
254
255static int rw_test(int rank)
256{
257 const u32 mask = 0xf00fc33c;
258 int ok = 0xff;
259 int i;
260 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800261 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100262 sfence();
263 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800264 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100265 sfence();
266 for (i = 0; i < 32; i++) {
267 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800268 write32p((rank << 28) | (i << 3), pat);
269 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270 }
271 sfence();
272 for (i = 0; i < 32; i++) {
273 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
274 int j;
275 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100277 for (j = 0; j < 4; j++)
278 if (((val >> (j * 8)) & 0xff) != pat)
279 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800280 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100281 for (j = 0; j < 4; j++)
282 if (((val >> (j * 8)) & 0xff) != pat)
283 ok &= ~(16 << j);
284 }
285 sfence();
286 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800287 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288 sfence();
289 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800290 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291
292 return ok;
293}
294
295static void
296program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
297{
298 int lane;
299 for (lane = 0; lane < 8; lane++) {
300 write_500(info, channel,
301 base +
302 info->training.
303 lane_timings[2][channel][slot][rank][lane],
304 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
305 write_500(info, channel,
306 base +
307 info->training.
308 lane_timings[3][channel][slot][rank][lane],
309 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
310 }
311}
312
313static void write_26c(int channel, u16 si)
314{
Felix Held04be2dd2018-07-29 04:53:22 +0200315 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
316 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
317 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100318}
319
320static u32 get_580(int channel, u8 addr)
321{
322 u32 ret;
323 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200324 MCHBAR8(0x5ff) = 0x0;
325 MCHBAR8(0x5ff) = 0x80;
326 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
327 MCHBAR8_OR(0x580 + (channel << 10), 1);
328 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
329 ;
330 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100331 return ret;
332}
333
334const int cached_config = 0;
335
336#define NUM_CHANNELS 2
337#define NUM_SLOTS 2
338#define NUM_RANKS 2
339#define RANK_SHIFT 28
340#define CHANNEL_SHIFT 10
341
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100342static void seq9(struct raminfo *info, int channel, int slot, int rank)
343{
344 int i, lane;
345
346 for (i = 0; i < 2; i++)
347 for (lane = 0; lane < 8; lane++)
348 write_500(info, channel,
349 info->training.lane_timings[i +
350 1][channel][slot]
351 [rank][lane], get_timing_register_addr(lane,
352 i + 1,
353 slot,
354 rank),
355 9, 0);
356
357 write_1d0(1, 0x103, 6, 1);
358 for (lane = 0; lane < 8; lane++)
359 write_500(info, channel,
360 info->training.
361 lane_timings[0][channel][slot][rank][lane],
362 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
363
364 for (i = 0; i < 2; i++) {
365 for (lane = 0; lane < 8; lane++)
366 write_500(info, channel,
367 info->training.lane_timings[i +
368 1][channel][slot]
369 [rank][lane], get_timing_register_addr(lane,
370 i + 1,
371 slot,
372 rank),
373 9, 0);
374 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
375 }
376
377 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200378 MCHBAR8(0x5ff) = 0x0;
379 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100380 write_1d0(0x2, 0x142, 3, 1);
381 for (lane = 0; lane < 8; lane++) {
382 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
383 info->training.lane_timings[2][channel][slot][rank][lane] =
384 read_500(info, channel,
385 get_timing_register_addr(lane, 2, slot, rank), 9);
386 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
387 info->training.lane_timings[3][channel][slot][rank][lane] =
388 info->training.lane_timings[2][channel][slot][rank][lane] +
389 0x20;
390 }
391}
392
393static int count_ranks_in_channel(struct raminfo *info, int channel)
394{
395 int slot, rank;
396 int res = 0;
397 for (slot = 0; slot < NUM_SLOTS; slot++)
398 for (rank = 0; rank < NUM_SLOTS; rank++)
399 res += info->populated_ranks[channel][slot][rank];
400 return res;
401}
402
403static void
404config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
405{
406 int add;
407
408 write_1d0(0, 0x178, 7, 1);
409 seq9(info, channel, slot, rank);
410 program_timings(info, 0x80, channel, slot, rank);
411
412 if (channel == 0)
413 add = count_ranks_in_channel(info, 1);
414 else
415 add = 0;
416 if (!s3resume)
417 gav(rw_test(rank + add));
418 program_timings(info, 0x00, channel, slot, rank);
419 if (!s3resume)
420 gav(rw_test(rank + add));
421 if (!s3resume)
422 gav(rw_test(rank + add));
423 write_1d0(0, 0x142, 3, 1);
424 write_1d0(0, 0x103, 6, 1);
425
426 gav(get_580(channel, 0xc | (rank << 5)));
427 gav(read_1d0(0x142, 3));
428
Felix Held04be2dd2018-07-29 04:53:22 +0200429 MCHBAR8(0x5ff) = 0x0;
430 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100431}
432
433static void set_4cf(struct raminfo *info, int channel, u8 val)
434{
435 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
436 write_500(info, channel, val, 0x4cf, 4, 1);
437 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
438 write_500(info, channel, val, 0x659, 4, 1);
439 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
440 write_500(info, channel, val, 0x697, 4, 1);
441}
442
443static void set_334(int zero)
444{
445 int j, k, channel;
446 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
447 u32 vd8[2][16];
448
449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
450 for (j = 0; j < 4; j++) {
451 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
452 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
453 u16 c;
454 if ((j == 0 || j == 3) && zero)
455 c = 0;
456 else if (j == 3)
457 c = 0x5f;
458 else
459 c = 0x5f5f;
460
461 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200462 MCHBAR32(0x138 + 8 * k) =
463 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100464 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200465 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100466 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200467 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100468 }
469
Felix Held22ca8cb2018-07-29 05:09:44 +0200470 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
471 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200472 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
473 zero ? 0 : (0x18191819 & lmask);
474 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
475 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
476 zero ? 0 : (a & lmask);
477 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
478 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100479 }
480 }
481
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32_OR(0x130, 1);
483 while (MCHBAR8(0x130) & 1)
484 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485}
486
487static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
488{
489 u32 v;
490 v = read_1d0(addr, split);
491 write_1d0((v & and) | or, addr, split, flag);
492}
493
494static int find_highest_bit_set(u16 val)
495{
496 int i;
497 for (i = 15; i >= 0; i--)
498 if (val & (1 << i))
499 return i;
500 return -1;
501}
502
503static int find_lowest_bit_set32(u32 val)
504{
505 int i;
506 for (i = 0; i < 32; i++)
507 if (val & (1 << i))
508 return i;
509 return -1;
510}
511
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100512enum {
513 DEVICE_TYPE = 2,
514 MODULE_TYPE = 3,
515 DENSITY = 4,
516 RANKS_AND_DQ = 7,
517 MEMORY_BUS_WIDTH = 8,
518 TIMEBASE_DIVIDEND = 10,
519 TIMEBASE_DIVISOR = 11,
520 CYCLETIME = 12,
521
522 CAS_LATENCIES_LSB = 14,
523 CAS_LATENCIES_MSB = 15,
524 CAS_LATENCY_TIME = 16,
525 THERMAL_AND_REFRESH = 31,
526 REFERENCE_RAW_CARD_USED = 62,
527 RANK1_ADDRESS_MAPPING = 63
528};
529
530static void calculate_timings(struct raminfo *info)
531{
Martin Roth468d02c2019-10-23 21:44:42 -0600532 unsigned int cycletime;
533 unsigned int cas_latency_time;
534 unsigned int supported_cas_latencies;
535 unsigned int channel, slot;
536 unsigned int clock_speed_index;
537 unsigned int min_cas_latency;
538 unsigned int cas_latency;
539 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100540
541 /* Find common CAS latency */
542 supported_cas_latencies = 0x3fe;
543 for (channel = 0; channel < NUM_CHANNELS; channel++)
544 for (slot = 0; slot < NUM_SLOTS; slot++)
545 if (info->populated_ranks[channel][slot][0])
546 supported_cas_latencies &=
547 2 *
548 (info->
549 spd[channel][slot][CAS_LATENCIES_LSB] |
550 (info->
551 spd[channel][slot][CAS_LATENCIES_MSB] <<
552 8));
553
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100554 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100555
556 cycletime = min_cycletime[max_clock_index];
557 cas_latency_time = min_cas_latency_time[max_clock_index];
558
559 for (channel = 0; channel < NUM_CHANNELS; channel++)
560 for (slot = 0; slot < NUM_SLOTS; slot++)
561 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600562 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100563 timebase =
564 1000 *
565 info->
566 spd[channel][slot][TIMEBASE_DIVIDEND] /
567 info->spd[channel][slot][TIMEBASE_DIVISOR];
568 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100569 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100570 timebase *
571 info->spd[channel][slot][CYCLETIME]);
572 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100573 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100574 timebase *
575 info->
576 spd[channel][slot][CAS_LATENCY_TIME]);
577 }
Jacob Garber3c193822019-06-10 18:23:32 -0600578 if (cycletime > min_cycletime[0])
579 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100580 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
581 if (cycletime == min_cycletime[clock_speed_index])
582 break;
583 if (cycletime > min_cycletime[clock_speed_index]) {
584 clock_speed_index--;
585 cycletime = min_cycletime[clock_speed_index];
586 break;
587 }
588 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100589 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100590 cas_latency = 0;
591 while (supported_cas_latencies) {
592 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
593 if (cas_latency <= min_cas_latency)
594 break;
595 supported_cas_latencies &=
596 ~(1 << find_highest_bit_set(supported_cas_latencies));
597 }
598
599 if (cas_latency != min_cas_latency && clock_speed_index)
600 clock_speed_index--;
601
602 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
603 die("Couldn't configure DRAM");
604 info->clock_speed_index = clock_speed_index;
605 info->cas_latency = cas_latency;
606}
607
608static void program_base_timings(struct raminfo *info)
609{
Martin Roth468d02c2019-10-23 21:44:42 -0600610 unsigned int channel;
611 unsigned int slot, rank, lane;
612 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100613 int i;
614
615 extended_silicon_revision = info->silicon_revision;
616 if (info->silicon_revision == 0)
617 for (channel = 0; channel < NUM_CHANNELS; channel++)
618 for (slot = 0; slot < NUM_SLOTS; slot++)
619 if ((info->
620 spd[channel][slot][MODULE_TYPE] & 0xF) ==
621 3)
622 extended_silicon_revision = 4;
623
624 for (channel = 0; channel < NUM_CHANNELS; channel++) {
625 for (slot = 0; slot < NUM_SLOTS; slot++)
626 for (rank = 0; rank < NUM_SLOTS; rank++) {
627 int card_timing_2;
628 if (!info->populated_ranks[channel][slot][rank])
629 continue;
630
631 for (lane = 0; lane < 9; lane++) {
632 int tm_reg;
633 int card_timing;
634
635 card_timing = 0;
636 if ((info->
637 spd[channel][slot][MODULE_TYPE] &
638 0xF) == 3) {
639 int reference_card;
640 reference_card =
641 info->
642 spd[channel][slot]
643 [REFERENCE_RAW_CARD_USED] &
644 0x1f;
645 if (reference_card == 3)
646 card_timing =
647 u16_ffd1188[0][lane]
648 [info->
649 clock_speed_index];
650 if (reference_card == 5)
651 card_timing =
652 u16_ffd1188[1][lane]
653 [info->
654 clock_speed_index];
655 }
656
657 info->training.
658 lane_timings[0][channel][slot][rank]
659 [lane] =
660 u8_FFFD1218[info->
661 clock_speed_index];
662 info->training.
663 lane_timings[1][channel][slot][rank]
664 [lane] = 256;
665
666 for (tm_reg = 2; tm_reg < 4; tm_reg++)
667 info->training.
668 lane_timings[tm_reg]
669 [channel][slot][rank][lane]
670 =
671 u8_FFFD1240[channel]
672 [extended_silicon_revision]
673 [lane][2 * slot +
674 rank][info->
675 clock_speed_index]
676 + info->max4048[channel]
677 +
678 u8_FFFD0C78[channel]
679 [extended_silicon_revision]
680 [info->
681 mode4030[channel]][slot]
682 [rank][info->
683 clock_speed_index]
684 + card_timing;
685 for (tm_reg = 0; tm_reg < 4; tm_reg++)
686 write_500(info, channel,
687 info->training.
688 lane_timings[tm_reg]
689 [channel][slot][rank]
690 [lane],
691 get_timing_register_addr
692 (lane, tm_reg, slot,
693 rank), 9, 0);
694 }
695
696 card_timing_2 = 0;
697 if (!(extended_silicon_revision != 4
698 || (info->
699 populated_ranks_mask[channel] & 5) ==
700 5)) {
701 if ((info->
702 spd[channel][slot]
703 [REFERENCE_RAW_CARD_USED] & 0x1F)
704 == 3)
705 card_timing_2 =
706 u16_FFFE0EB8[0][info->
707 clock_speed_index];
708 if ((info->
709 spd[channel][slot]
710 [REFERENCE_RAW_CARD_USED] & 0x1F)
711 == 5)
712 card_timing_2 =
713 u16_FFFE0EB8[1][info->
714 clock_speed_index];
715 }
716
717 for (i = 0; i < 3; i++)
718 write_500(info, channel,
719 (card_timing_2 +
720 info->max4048[channel]
721 +
722 u8_FFFD0EF8[channel]
723 [extended_silicon_revision]
724 [info->
725 mode4030[channel]][info->
726 clock_speed_index]),
727 u16_fffd0c50[i][slot][rank],
728 8, 1);
729 write_500(info, channel,
730 (info->max4048[channel] +
731 u8_FFFD0C78[channel]
732 [extended_silicon_revision][info->
733 mode4030
734 [channel]]
735 [slot][rank][info->
736 clock_speed_index]),
737 u16_fffd0c70[slot][rank], 7, 1);
738 }
739 if (!info->populated_ranks_mask[channel])
740 continue;
741 for (i = 0; i < 3; i++)
742 write_500(info, channel,
743 (info->max4048[channel] +
744 info->avg4044[channel]
745 +
746 u8_FFFD17E0[channel]
747 [extended_silicon_revision][info->
748 mode4030
749 [channel]][info->
750 clock_speed_index]),
751 u16_fffd0c68[i], 8, 1);
752 }
753}
754
755static unsigned int fsbcycle_ps(struct raminfo *info)
756{
757 return 900000 / info->fsb_frequency;
758}
759
760/* The time of DDR transfer in ps. */
761static unsigned int halfcycle_ps(struct raminfo *info)
762{
763 return 3750 / (info->clock_speed_index + 3);
764}
765
766/* The time of clock cycle in ps. */
767static unsigned int cycle_ps(struct raminfo *info)
768{
769 return 2 * halfcycle_ps(info);
770}
771
772/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600773static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100774{
775 return (info->clock_speed_index + 3) * 120;
776}
777
778/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600779static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100780{
781 return 100 * frequency_11(info) / 9;
782}
783
Martin Roth468d02c2019-10-23 21:44:42 -0600784static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100785{
786 return (frequency_11(info) * 2) * ps / 900000;
787}
788
Martin Roth468d02c2019-10-23 21:44:42 -0600789static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100790{
791 return (frequency_11(info)) * ns / 900;
792}
793
794static void compute_derived_timings(struct raminfo *info)
795{
Martin Roth468d02c2019-10-23 21:44:42 -0600796 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100797 int extended_silicon_revision;
798 int some_delay_1_ps;
799 int some_delay_2_ps;
800 int some_delay_2_halfcycles_ceil;
801 int some_delay_2_halfcycles_floor;
802 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100803 int some_delay_3_ps_rounded;
804 int some_delay_1_cycle_ceil;
805 int some_delay_1_cycle_floor;
806
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100807 some_delay_3_ps_rounded = 0;
808 extended_silicon_revision = info->silicon_revision;
809 if (!info->silicon_revision)
810 for (channel = 0; channel < NUM_CHANNELS; channel++)
811 for (slot = 0; slot < NUM_SLOTS; slot++)
812 if ((info->
813 spd[channel][slot][MODULE_TYPE] & 0xF) ==
814 3)
815 extended_silicon_revision = 4;
816 if (info->board_lane_delay[7] < 5)
817 info->board_lane_delay[7] = 5;
818 info->revision_flag_1 = 2;
819 if (info->silicon_revision == 2 || info->silicon_revision == 3)
820 info->revision_flag_1 = 0;
821 if (info->revision < 16)
822 info->revision_flag_1 = 0;
823
824 if (info->revision < 8)
825 info->revision_flag_1 = 0;
826 if (info->revision >= 8 && (info->silicon_revision == 0
827 || info->silicon_revision == 1))
828 some_delay_2_ps = 735;
829 else
830 some_delay_2_ps = 750;
831
832 if (info->revision >= 0x10 && (info->silicon_revision == 0
833 || info->silicon_revision == 1))
834 some_delay_1_ps = 3929;
835 else
836 some_delay_1_ps = 3490;
837
838 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
839 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
840 if (some_delay_1_ps % cycle_ps(info))
841 some_delay_1_cycle_ceil++;
842 else
843 some_delay_1_cycle_floor--;
844 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
845 if (info->revision_flag_1)
846 some_delay_2_ps = halfcycle_ps(info) >> 6;
847 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100848 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100849 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
850 375;
851 some_delay_3_ps =
852 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
853 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200854 if (some_delay_3_ps >= 150) {
855 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100856 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200857 some_delay_3_ps_rounded =
858 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
859 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100860 }
861 some_delay_2_halfcycles_ceil =
862 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
863 2 * (some_delay_1_cycle_ceil - 1);
864 if (info->revision_flag_1 && some_delay_3_ps < 150)
865 some_delay_2_halfcycles_ceil++;
866 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
867 if (info->revision < 0x10)
868 some_delay_2_halfcycles_floor =
869 some_delay_2_halfcycles_ceil - 1;
870 if (!info->revision_flag_1)
871 some_delay_2_halfcycles_floor++;
872 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
873 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
874 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
875 || (info->populated_ranks[1][0][0]
876 && info->populated_ranks[1][1][0]))
877 info->max_slots_used_in_channel = 2;
878 else
879 info->max_slots_used_in_channel = 1;
880 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200881 MCHBAR32(0x244 + (channel << 10)) =
882 ((info->revision < 8) ? 1 : 0x200) |
883 ((2 - info->max_slots_used_in_channel) << 17) |
884 (channel << 21) |
885 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100886 if (info->max_slots_used_in_channel == 1) {
887 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
888 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
889 } else {
890 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
891 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
892 || (count_ranks_in_channel(info, 1) ==
893 2)) ? 2 : 3;
894 }
895 for (channel = 0; channel < NUM_CHANNELS; channel++) {
896 int max_of_unk;
897 int min_of_unk_2;
898
899 int i, count;
900 int sum;
901
902 if (!info->populated_ranks_mask[channel])
903 continue;
904
905 max_of_unk = 0;
906 min_of_unk_2 = 32767;
907
908 sum = 0;
909 count = 0;
910 for (i = 0; i < 3; i++) {
911 int unk1;
912 if (info->revision < 8)
913 unk1 =
914 u8_FFFD1891[0][channel][info->
915 clock_speed_index]
916 [i];
917 else if (!
918 (info->revision >= 0x10
919 || info->revision_flag_1))
920 unk1 =
921 u8_FFFD1891[1][channel][info->
922 clock_speed_index]
923 [i];
924 else
925 unk1 = 0;
926 for (slot = 0; slot < NUM_SLOTS; slot++)
927 for (rank = 0; rank < NUM_RANKS; rank++) {
928 int a = 0;
929 int b = 0;
930
931 if (!info->
932 populated_ranks[channel][slot]
933 [rank])
934 continue;
935 if (extended_silicon_revision == 4
936 && (info->
937 populated_ranks_mask[channel] &
938 5) != 5) {
939 if ((info->
940 spd[channel][slot]
941 [REFERENCE_RAW_CARD_USED] &
942 0x1F) == 3) {
943 a = u16_ffd1178[0]
944 [info->
945 clock_speed_index];
946 b = u16_fe0eb8[0][info->
947 clock_speed_index];
948 } else
949 if ((info->
950 spd[channel][slot]
951 [REFERENCE_RAW_CARD_USED]
952 & 0x1F) == 5) {
953 a = u16_ffd1178[1]
954 [info->
955 clock_speed_index];
956 b = u16_fe0eb8[1][info->
957 clock_speed_index];
958 }
959 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100960 min_of_unk_2 = MIN(min_of_unk_2, a);
961 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100962 if (rank == 0) {
963 sum += a;
964 count++;
965 }
966 {
967 int t;
968 t = b +
969 u8_FFFD0EF8[channel]
970 [extended_silicon_revision]
971 [info->
972 mode4030[channel]][info->
973 clock_speed_index];
974 if (unk1 >= t)
975 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100976 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100977 unk1 - t);
978 }
979 }
980 {
981 int t =
982 u8_FFFD17E0[channel]
983 [extended_silicon_revision][info->
984 mode4030
985 [channel]]
986 [info->clock_speed_index] + min_of_unk_2;
987 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100988 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100989 }
990 }
991
Jacob Garber64fb4a32019-06-10 17:29:18 -0600992 if (count == 0)
993 die("No memory ranks found for channel %u\n", channel);
994
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100995 info->avg4044[channel] = sum / count;
996 info->max4048[channel] = max_of_unk;
997 }
998}
999
1000static void jedec_read(struct raminfo *info,
1001 int channel, int slot, int rank,
1002 int total_rank, u8 addr3, unsigned int value)
1003{
1004 /* Handle mirrored mapping. */
1005 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001006 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1007 ((addr3 >> 1) & 0x10);
1008 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1009 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001010
1011 /* Handle mirrored mapping. */
1012 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1013 value =
1014 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1015 << 1);
1016
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001017 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001018
Felix Held04be2dd2018-07-29 04:53:22 +02001019 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1020 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001021
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001022 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001023}
1024
1025enum {
1026 MR1_RZQ12 = 512,
1027 MR1_RZQ2 = 64,
1028 MR1_RZQ4 = 4,
1029 MR1_ODS34OHM = 2
1030};
1031
1032enum {
1033 MR0_BT_INTERLEAVED = 8,
1034 MR0_DLL_RESET_ON = 256
1035};
1036
1037enum {
1038 MR2_RTT_WR_DISABLED = 0,
1039 MR2_RZQ2 = 1 << 10
1040};
1041
1042static void jedec_init(struct raminfo *info)
1043{
1044 int write_recovery;
1045 int channel, slot, rank;
1046 int total_rank;
1047 int dll_on;
1048 int self_refresh_temperature;
1049 int auto_self_refresh;
1050
1051 auto_self_refresh = 1;
1052 self_refresh_temperature = 1;
1053 if (info->board_lane_delay[3] <= 10) {
1054 if (info->board_lane_delay[3] <= 8)
1055 write_recovery = info->board_lane_delay[3] - 4;
1056 else
1057 write_recovery = 5;
1058 } else {
1059 write_recovery = 6;
1060 }
1061 FOR_POPULATED_RANKS {
1062 auto_self_refresh &=
1063 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1064 self_refresh_temperature &=
1065 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1066 }
1067 if (auto_self_refresh == 1)
1068 self_refresh_temperature = 0;
1069
1070 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1071 || (info->populated_ranks[0][0][0]
1072 && info->populated_ranks[0][1][0])
1073 || (info->populated_ranks[1][0][0]
1074 && info->populated_ranks[1][1][0]));
1075
1076 total_rank = 0;
1077
1078 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1079 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1080 int rzq_reg58e;
1081
1082 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1083 rzq_reg58e = 64;
1084 rtt = MR1_RZQ2;
1085 if (info->clock_speed_index != 0) {
1086 rzq_reg58e = 4;
1087 if (info->populated_ranks_mask[channel] == 3)
1088 rtt = MR1_RZQ4;
1089 }
1090 } else {
1091 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1092 rtt = MR1_RZQ12;
1093 rzq_reg58e = 64;
1094 rtt_wr = MR2_RZQ2;
1095 } else {
1096 rzq_reg58e = 4;
1097 rtt = MR1_RZQ4;
1098 }
1099 }
1100
Felix Held04be2dd2018-07-29 04:53:22 +02001101 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1102 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1103 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1104 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1105 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001106
1107 for (slot = 0; slot < NUM_SLOTS; slot++)
1108 for (rank = 0; rank < NUM_RANKS; rank++)
1109 if (info->populated_ranks[channel][slot][rank]) {
1110 jedec_read(info, channel, slot, rank,
1111 total_rank, 0x28,
1112 rtt_wr | (info->
1113 clock_speed_index
1114 << 3)
1115 | (auto_self_refresh << 6) |
1116 (self_refresh_temperature <<
1117 7));
1118 jedec_read(info, channel, slot, rank,
1119 total_rank, 0x38, 0);
1120 jedec_read(info, channel, slot, rank,
1121 total_rank, 0x18,
1122 rtt | MR1_ODS34OHM);
1123 jedec_read(info, channel, slot, rank,
1124 total_rank, 6,
1125 (dll_on << 12) |
1126 (write_recovery << 9)
1127 | ((info->cas_latency - 4) <<
1128 4) | MR0_BT_INTERLEAVED |
1129 MR0_DLL_RESET_ON);
1130 total_rank++;
1131 }
1132 }
1133}
1134
1135static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1136{
Martin Roth468d02c2019-10-23 21:44:42 -06001137 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001138 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1139 unsigned int channel_0_non_interleaved;
1140
1141 FOR_ALL_RANKS {
1142 if (info->populated_ranks[channel][slot][rank]) {
1143 total_mb[channel] +=
1144 pre_jedec ? 256 : (256 << info->
1145 density[channel][slot] >> info->
1146 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001147 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1148 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1149 (info->is_x16_module[channel][slot] |
1150 ((info->density[channel][slot] + 1) << 1))) |
1151 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001152 }
Felix Held04be2dd2018-07-29 04:53:22 +02001153 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1154 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001155 }
1156
1157 info->total_memory_mb = total_mb[0] + total_mb[1];
1158
1159 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001160 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 info->non_interleaved_part_mb =
1162 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1163 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001164 MCHBAR32(0x100) = channel_0_non_interleaved |
1165 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001166 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001167 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001168}
1169
1170static void program_board_delay(struct raminfo *info)
1171{
1172 int cas_latency_shift;
1173 int some_delay_ns;
1174 int some_delay_3_half_cycles;
1175
Martin Roth468d02c2019-10-23 21:44:42 -06001176 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001177 int high_multiplier;
1178 int lane_3_delay;
1179 int cas_latency_derived;
1180
1181 high_multiplier = 0;
1182 some_delay_ns = 200;
1183 some_delay_3_half_cycles = 4;
1184 cas_latency_shift = info->silicon_revision == 0
1185 || info->silicon_revision == 1 ? 1 : 0;
1186 if (info->revision < 8) {
1187 some_delay_ns = 600;
1188 cas_latency_shift = 0;
1189 }
1190 {
1191 int speed_bit;
1192 speed_bit =
1193 ((info->clock_speed_index > 1
1194 || (info->silicon_revision != 2
1195 && info->silicon_revision != 3))) ^ (info->revision >=
1196 0x10);
1197 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1198 3, 1);
1199 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1200 3, 1);
1201 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1202 && (info->silicon_revision == 2
1203 || info->silicon_revision == 3))
1204 rmw_1d0(0x116, 5, 2, 4, 1);
1205 }
Felix Held04be2dd2018-07-29 04:53:22 +02001206 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1207 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001208
Felix Held04be2dd2018-07-29 04:53:22 +02001209 MCHBAR8(0x124) = info->board_lane_delay[4] +
1210 ((frequency_01(info) + 999) / 1000);
1211 MCHBAR16(0x125) = 0x1360;
1212 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001213 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001214 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001215 high_multiplier = 1;
1216 some_delay_2_half_cycles = ps_to_halfcycles(info,
1217 ((3 *
1218 fsbcycle_ps(info))
1219 >> 1) +
1220 (halfcycle_ps(info)
1221 *
1222 reg178_min[info->
1223 clock_speed_index]
1224 >> 6)
1225 +
1226 4 *
1227 halfcycle_ps(info)
1228 + 2230);
1229 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001230 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001231 (frequency_11(info) * 2) * (28 -
1232 some_delay_2_half_cycles) /
1233 (frequency_11(info) * 2 -
1234 4 * (info->fsb_frequency))) >> 3, 7);
1235 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001236 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001237 some_delay_3_half_cycles = 3;
1238 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001239 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1240 MCHBAR32(0x224 + (channel << 10)) =
1241 (info->max_slots_used_in_channel - 1) |
1242 ((info->cas_latency - 5 - info->clock_speed_index)
1243 << 21) | ((info->max_slots_used_in_channel +
1244 info->cas_latency - cas_latency_shift - 4) << 16) |
1245 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1246 ((info->cas_latency - info->clock_speed_index +
1247 info->max_slots_used_in_channel - 6) << 8);
1248 MCHBAR32(0x228 + (channel << 10)) =
1249 info->max_slots_used_in_channel;
1250 MCHBAR8(0x239 + (channel << 10)) = 32;
1251 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1252 (some_delay_3_half_cycles << 25) | 0x840000;
1253 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1254 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1255 MCHBAR32(0x24c + (channel << 10)) =
1256 ((!!info->clock_speed_index) << 17) |
1257 (((2 + info->clock_speed_index -
1258 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001259
Felix Held04be2dd2018-07-29 04:53:22 +02001260 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1261 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1262 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001263
1264 write_500(info, channel,
1265 ((!info->populated_ranks[channel][1][1])
1266 | (!info->populated_ranks[channel][1][0] << 1)
1267 | (!info->populated_ranks[channel][0][1] << 2)
1268 | (!info->populated_ranks[channel][0][0] << 3)),
1269 0x4c9, 4, 1);
1270 }
1271
Felix Held22ca8cb2018-07-29 05:09:44 +02001272 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001273 {
1274 u8 freq_divisor = 2;
1275 if (info->fsb_frequency == frequency_11(info))
1276 freq_divisor = 3;
1277 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1278 freq_divisor = 1;
1279 else
1280 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001281 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001282 }
1283
1284 if (info->board_lane_delay[3] <= 10) {
1285 if (info->board_lane_delay[3] <= 8)
1286 lane_3_delay = info->board_lane_delay[3];
1287 else
1288 lane_3_delay = 10;
1289 } else {
1290 lane_3_delay = 12;
1291 }
1292 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1293 if (info->clock_speed_index > 1)
1294 cas_latency_derived++;
1295 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001296 MCHBAR32(0x240 + (channel << 10)) =
1297 ((info->clock_speed_index == 0) * 0x11000) |
1298 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1299 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001300 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1301 0x609, 6, 1);
1302 write_500(info, channel,
1303 info->clock_speed_index + 2 * info->cas_latency - 7,
1304 0x601, 6, 1);
1305
Felix Held04be2dd2018-07-29 04:53:22 +02001306 MCHBAR32(0x250 + (channel << 10)) =
1307 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1308 (info->board_lane_delay[7] << 2) |
1309 (info->board_lane_delay[4] << 16) |
1310 (info->board_lane_delay[1] << 25) |
1311 (info->board_lane_delay[1] << 29) | 1;
1312 MCHBAR32(0x254 + (channel << 10)) =
1313 (info->board_lane_delay[1] >> 3) |
1314 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1315 0x80 | (info->board_lane_delay[6] << 1) |
1316 (info->board_lane_delay[2] << 28) |
1317 (cas_latency_derived << 16) | 0x4700000;
1318 MCHBAR32(0x258 + (channel << 10)) =
1319 ((info->board_lane_delay[5] + info->clock_speed_index +
1320 9) << 12) | ((info->clock_speed_index -
1321 info->cas_latency + 12) << 8) |
1322 (info->board_lane_delay[2] << 17) |
1323 (info->board_lane_delay[4] << 24) | 0x47;
1324 MCHBAR32(0x25c + (channel << 10)) =
1325 (info->board_lane_delay[1] << 1) |
1326 (info->board_lane_delay[0] << 8) | 0x1da50000;
1327 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1328 MCHBAR8(0x5f8 + (channel << 10)) =
1329 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001330 }
1331
1332 program_modules_memory_map(info, 1);
1333
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001334 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001335 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1336 MCHBAR16_OR(0x612, 0x100);
1337 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001338 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001339 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001340 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001341 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001342 }
1343}
1344
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001345#define DEFAULT_PCI_MMIO_SIZE 2048
1346#define HOST_BRIDGE PCI_DEVFN(0, 0)
1347
1348static unsigned int get_mmio_size(void)
1349{
1350 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001351 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001352
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001353 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001354 if (dev)
1355 cfg = dev->chip_info;
1356
1357 /* If this is zero, it just means devicetree.cb didn't set it */
1358 if (!cfg || cfg->pci_mmio_size == 0)
1359 return DEFAULT_PCI_MMIO_SIZE;
1360 else
1361 return cfg->pci_mmio_size;
1362}
1363
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001364static void program_total_memory_map(struct raminfo *info)
1365{
Angel Pons9333b742020-07-22 16:04:15 +02001366 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001367 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001368 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001369 unsigned int uma_base_igd;
1370 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001371 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001372 int memory_remap;
1373 unsigned int memory_map[8];
1374 int i;
1375 unsigned int current_limit;
1376 unsigned int tseg_base;
1377 int uma_size_igd = 0, uma_size_gtt = 0;
1378
1379 memset(memory_map, 0, sizeof(memory_map));
1380
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001381 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001382 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001383 gav(t);
1384 const int uma_sizes_gtt[16] =
1385 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1386 /* Igd memory */
1387 const int uma_sizes_igd[16] = {
1388 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1389 256, 512
1390 };
1391
1392 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1393 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1394 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001396 mmio_size = get_mmio_size();
1397
Angel Pons9333b742020-07-22 16:04:15 +02001398 tom = info->total_memory_mb;
1399 if (tom == 4096)
1400 tom = 4032;
1401 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1402 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1403 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001404 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001405 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001407 remap_base = MAX(4096, touud);
1408 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001409 }
Angel Pons9333b742020-07-22 16:04:15 +02001410 if (touud > 4096)
1411 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 quickpath_reserved = 0;
1413
Angel Pons3ab19b32020-07-22 16:29:54 +02001414 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415
Jacob Garber975a7e32019-06-10 16:32:47 -06001416 gav(t);
1417
1418 if (t & 0x800) {
1419 u32 shift = t >> 20;
1420 if (shift == 0)
1421 die("Quickpath value is 0\n");
1422 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001424
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001425 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001426 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001427
Angel Pons9333b742020-07-22 16:04:15 +02001428 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 uma_base_gtt = uma_base_igd - uma_size_gtt;
1430 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1431 if (!memory_remap)
1432 tseg_base -= quickpath_reserved;
1433 tseg_base = ALIGN_DOWN(tseg_base, 8);
1434
Angel Pons16fe1e02020-07-22 16:12:33 +02001435 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1436 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001438 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1439 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001441 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442
1443 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001444 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1445 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001447 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448
1449 current_limit = 0;
1450 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1451 memory_map[1] = 4096;
1452 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001453 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001454 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1456 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001457 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458 }
1459}
1460
1461static void collect_system_info(struct raminfo *info)
1462{
1463 u32 capid0[3];
1464 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001465 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466
1467 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001468 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1469 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 if (!info->memory_reserved_for_heci_mb) {
1472 /* Wait for ME to be ready */
1473 intel_early_me_init();
1474 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1475 }
1476
1477 for (i = 0; i < 3; i++)
1478 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001479 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001480 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1482
1483 if ((capid0[1] >> 11) & 1)
1484 info->uma_enabled = 0;
1485 else
1486 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001487 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1489 info->silicon_revision = 0;
1490
1491 if (capid0[2] & 2) {
1492 info->silicon_revision = 0;
1493 info->max_supported_clock_speed_index = 2;
1494 for (channel = 0; channel < NUM_CHANNELS; channel++)
1495 if (info->populated_ranks[channel][0][0]
1496 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1497 3) {
1498 info->silicon_revision = 2;
1499 info->max_supported_clock_speed_index = 1;
1500 }
1501 } else {
1502 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1503 case 1:
1504 case 2:
1505 info->silicon_revision = 3;
1506 break;
1507 case 3:
1508 info->silicon_revision = 0;
1509 break;
1510 case 0:
1511 info->silicon_revision = 2;
1512 break;
1513 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001514 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001515 case 0x40:
1516 info->silicon_revision = 0;
1517 break;
1518 case 0x48:
1519 info->silicon_revision = 1;
1520 break;
1521 }
1522 }
1523}
1524
1525static void write_training_data(struct raminfo *info)
1526{
1527 int tm, channel, slot, rank, lane;
1528 if (info->revision < 8)
1529 return;
1530
1531 for (tm = 0; tm < 4; tm++)
1532 for (channel = 0; channel < NUM_CHANNELS; channel++)
1533 for (slot = 0; slot < NUM_SLOTS; slot++)
1534 for (rank = 0; rank < NUM_RANKS; rank++)
1535 for (lane = 0; lane < 9; lane++)
1536 write_500(info, channel,
1537 info->
1538 cached_training->
1539 lane_timings[tm]
1540 [channel][slot][rank]
1541 [lane],
1542 get_timing_register_addr
1543 (lane, tm, slot,
1544 rank), 9, 0);
1545 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1546 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1547}
1548
1549static void dump_timings(struct raminfo *info)
1550{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001551 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001552 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001553 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001554 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001555 slot, rank);
1556 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001557 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001558 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001559 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001560 read_500(info, channel,
1561 get_timing_register_addr
1562 (lane, i, slot, rank),
1563 9),
1564 info->training.
1565 lane_timings[i][channel][slot][rank]
1566 [lane]);
1567 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001568 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 }
1570 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575}
1576
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001577/* Read timings and other registers that need to be restored verbatim and
1578 put them to CBMEM.
1579 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580static void save_timings(struct raminfo *info)
1581{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 int channel, slot, rank, lane, i;
1584
1585 train = info->training;
1586 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1587 for (i = 0; i < 4; i++)
1588 train.lane_timings[i][channel][slot][rank][lane] =
1589 read_500(info, channel,
1590 get_timing_register_addr(lane, i, slot,
1591 rank), 9);
1592 train.reg_178 = read_1d0(0x178, 7);
1593 train.reg_10b = read_1d0(0x10b, 6);
1594
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1596 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001597 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001598 train.reg274265[channel][0] = reg32 >> 16;
1599 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001600 train.reg274265[channel][2] =
1601 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001602 }
Felix Held04be2dd2018-07-29 04:53:22 +02001603 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1604 train.reg_6dc = MCHBAR32(0x6dc);
1605 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001606
Arthur Heymansb3282092019-04-14 17:53:28 +02001607 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1608 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001609
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001611 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1612 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001613}
1614
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615static const struct ram_training *get_cached_training(void)
1616{
Shelley Chenad9cd682020-07-23 16:10:52 -07001617 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1618 MRC_CACHE_VERSION,
1619 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621
1622/* FIXME: add timeout. */
1623static void wait_heci_ready(void)
1624{
Felix Held04be2dd2018-07-29 04:53:22 +02001625 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1626 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001627 write32((DEFAULT_HECIBAR + 0x4),
1628 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629}
1630
1631/* FIXME: add timeout. */
1632static void wait_heci_cb_avail(int len)
1633{
1634 union {
1635 struct mei_csr csr;
1636 u32 raw;
1637 } csr;
1638
Felix Held22ca8cb2018-07-29 05:09:44 +02001639 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1640 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641
1642 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001643 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001644 while (len >
1645 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001646 csr.csr.buffer_read_ptr))
1647 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648}
1649
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001650static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651{
1652 int len = (head->length + 3) / 4;
1653 int i;
1654
1655 wait_heci_cb_avail(len + 1);
1656
1657 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001658 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001660 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001661
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001662 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1663 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664}
1665
1666static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001667send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668{
1669 struct mei_header head;
1670 int maxlen;
1671
1672 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001673 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001674
1675 while (len) {
1676 int cur = len;
1677 if (cur > maxlen) {
1678 cur = maxlen;
1679 head.is_complete = 0;
1680 } else
1681 head.is_complete = 1;
1682 head.length = cur;
1683 head.reserved = 0;
1684 head.client_address = clientaddress;
1685 head.host_address = hostaddress;
1686 send_heci_packet(&head, (u32 *) msg);
1687 len -= cur;
1688 msg += cur;
1689 }
1690}
1691
1692/* FIXME: Add timeout. */
1693static int
Angel Pons86907462020-09-14 18:48:59 +02001694recv_heci_packet(struct mei_header *head, u32 *packet,
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001695 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696{
1697 union {
1698 struct mei_csr csr;
1699 u32 raw;
1700 } csr;
1701 int i = 0;
1702
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001703 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001705 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001706 }
Felix Held04be2dd2018-07-29 04:53:22 +02001707 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1708 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001709 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001711 write32(DEFAULT_HECIBAR + 0x4,
1712 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001713 *packet_size = 0;
1714 return 0;
1715 }
1716 if (head->length + 4 > 4 * csr.csr.buffer_depth
1717 || head->length > *packet_size) {
1718 *packet_size = 0;
1719 return -1;
1720 }
1721
1722 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001724 while (((head->length + 3) >> 2) >
1725 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1726 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727
1728 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 *packet_size = head->length;
1731 if (!csr.csr.ready)
1732 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001733 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 return 0;
1735}
1736
1737/* FIXME: Add timeout. */
1738static int
Angel Pons86907462020-09-14 18:48:59 +02001739recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740{
1741 struct mei_header head;
1742 int current_position;
1743
1744 current_position = 0;
1745 while (1) {
1746 u32 current_size;
1747 current_size = *message_size - current_position;
1748 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001749 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750 &current_size) == -1)
1751 break;
1752 if (!current_size)
1753 break;
1754 current_position += current_size;
1755 if (head.is_complete) {
1756 *message_size = current_position;
1757 return 0;
1758 }
1759
1760 if (current_position >= *message_size)
1761 break;
1762 }
1763 *message_size = 0;
1764 return -1;
1765}
1766
1767static void send_heci_uma_message(struct raminfo *info)
1768{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001769 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001770 u8 group_id;
1771 u8 command;
1772 u8 reserved;
1773 u8 result;
1774 u8 field2;
1775 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001776 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001777
1778 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1779 reply.command = 0;
1780
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001781 struct uma_message {
1782 u8 group_id;
1783 u8 cmd;
1784 u8 reserved;
1785 u8 result;
1786 u32 c2;
1787 u64 heci_uma_addr;
1788 u32 memory_reserved_for_heci_mb;
1789 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001790 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001791 0, MKHI_SET_UMA, 0, 0,
1792 0x82,
1793 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1794 u32 reply_size;
1795
1796 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1797
1798 reply_size = sizeof(reply);
Angel Pons86907462020-09-14 18:48:59 +02001799 if (recv_heci_message((u32 *) & reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001800 return;
1801
1802 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1803 die("HECI init failed\n");
1804}
1805
1806static void setup_heci_uma(struct raminfo *info)
1807{
1808 u32 reg44;
1809
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001810 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001811 info->memory_reserved_for_heci_mb = 0;
1812 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001813 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001814 return;
1815
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001816 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1817 info->heci_uma_addr =
1818 ((u64)
Angel Pons16fe1e02020-07-22 16:12:33 +02001819 ((((u64) pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001820 info->memory_reserved_for_heci_mb)) << 20;
1821
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001822 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001823 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001824 write32(DEFAULT_DMIBAR + 0x14,
1825 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1826 write32(DEFAULT_RCBA + 0x14,
1827 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1828 write32(DEFAULT_DMIBAR + 0x20,
1829 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1830 write32(DEFAULT_RCBA + 0x20,
1831 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1832 write32(DEFAULT_DMIBAR + 0x2c,
1833 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1834 write32(DEFAULT_RCBA + 0x30,
1835 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1836 write32(DEFAULT_DMIBAR + 0x38,
1837 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1838 write32(DEFAULT_RCBA + 0x40,
1839 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001841 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1842 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001843 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1844 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1845 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846 }
1847
Felix Held04be2dd2018-07-29 04:53:22 +02001848 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849
1850 send_heci_uma_message(info);
1851
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001852 pci_write_config32(HECIDEV, 0x10, 0x0);
1853 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001854
1855}
1856
1857static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1858{
1859 int ranks_in_channel;
1860 ranks_in_channel = info->populated_ranks[channel][0][0]
1861 + info->populated_ranks[channel][0][1]
1862 + info->populated_ranks[channel][1][0]
1863 + info->populated_ranks[channel][1][1];
1864
1865 /* empty channel */
1866 if (ranks_in_channel == 0)
1867 return 1;
1868
1869 if (ranks_in_channel != ranks)
1870 return 0;
1871 /* single slot */
1872 if (info->populated_ranks[channel][0][0] !=
1873 info->populated_ranks[channel][1][0])
1874 return 1;
1875 if (info->populated_ranks[channel][0][1] !=
1876 info->populated_ranks[channel][1][1])
1877 return 1;
1878 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1879 return 0;
1880 if (info->density[channel][0] != info->density[channel][1])
1881 return 0;
1882 return 1;
1883}
1884
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001885static void read_4090(struct raminfo *info)
1886{
1887 int i, channel, slot, rank, lane;
1888 for (i = 0; i < 2; i++)
1889 for (slot = 0; slot < NUM_SLOTS; slot++)
1890 for (rank = 0; rank < NUM_RANKS; rank++)
1891 for (lane = 0; lane < 9; lane++)
1892 info->training.
1893 lane_timings[0][i][slot][rank][lane]
1894 = 32;
1895
1896 for (i = 1; i < 4; i++)
1897 for (channel = 0; channel < NUM_CHANNELS; channel++)
1898 for (slot = 0; slot < NUM_SLOTS; slot++)
1899 for (rank = 0; rank < NUM_RANKS; rank++)
1900 for (lane = 0; lane < 9; lane++) {
1901 info->training.
1902 lane_timings[i][channel]
1903 [slot][rank][lane] =
1904 read_500(info, channel,
1905 get_timing_register_addr
1906 (lane, i, slot,
1907 rank), 9)
1908 + (i == 1) * 11; // !!!!
1909 }
1910
1911}
1912
1913static u32 get_etalon2(int flip, u32 addr)
1914{
1915 const u16 invmask[] = {
1916 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1917 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1918 };
1919 u32 ret;
1920 u32 comp4 = addr / 480;
1921 addr %= 480;
1922 u32 comp1 = addr & 0xf;
1923 u32 comp2 = (addr >> 4) & 1;
1924 u32 comp3 = addr >> 5;
1925
1926 if (comp4)
1927 ret = 0x1010101 << (comp4 - 1);
1928 else
1929 ret = 0;
1930 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1931 ret = ~ret;
1932
1933 return ret;
1934}
1935
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001936static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001937{
1938 msr_t msr = {.lo = 0, .hi = 0 };
1939
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001940 wrmsr(MTRR_PHYS_BASE(3), msr);
1941 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001942}
1943
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001944static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945{
1946 msr_t msr;
1947 msr.lo = base | MTRR_TYPE_WRPROT;
1948 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001949 wrmsr(MTRR_PHYS_BASE(3), msr);
1950 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001951 & 0xffffffff);
1952 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001953 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001954}
1955
1956static void flush_cache(u32 start, u32 size)
1957{
1958 u32 end;
1959 u32 addr;
1960
1961 end = start + (ALIGN_DOWN(size + 4096, 4096));
1962 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001963 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001964}
1965
1966static void clear_errors(void)
1967{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001968 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969}
1970
1971static void write_testing(struct raminfo *info, int totalrank, int flip)
1972{
1973 int nwrites = 0;
1974 /* in 8-byte units. */
1975 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001976 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001977
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001978 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001979 for (offset = 0; offset < 9 * 480; offset += 2) {
1980 write32(base + offset * 8, get_etalon2(flip, offset));
1981 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1982 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1983 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1984 nwrites += 4;
1985 if (nwrites >= 320) {
1986 clear_errors();
1987 nwrites = 0;
1988 }
1989 }
1990}
1991
1992static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1993{
1994 u8 failmask = 0;
1995 int i;
1996 int comp1, comp2, comp3;
1997 u32 failxor[2] = { 0, 0 };
1998
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001999 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002000
2001 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2002 for (comp1 = 0; comp1 < 4; comp1++)
2003 for (comp2 = 0; comp2 < 60; comp2++) {
2004 u32 re[4];
2005 u32 curroffset =
2006 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2007 read128((total_rank << 28) | (curroffset << 3),
2008 (u64 *) re);
2009 failxor[0] |=
2010 get_etalon2(flip, curroffset) ^ re[0];
2011 failxor[1] |=
2012 get_etalon2(flip, curroffset) ^ re[1];
2013 failxor[0] |=
2014 get_etalon2(flip, curroffset | 1) ^ re[2];
2015 failxor[1] |=
2016 get_etalon2(flip, curroffset | 1) ^ re[3];
2017 }
2018 for (i = 0; i < 8; i++)
2019 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2020 failmask |= 1 << i;
2021 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002022 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002023 flush_cache((total_rank << 28), 1728 * 5 * 4);
2024 return failmask;
2025}
2026
2027const u32 seed1[0x18] = {
2028 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2029 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2030 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2031 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2032 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2033 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2034};
2035
2036static u32 get_seed2(int a, int b)
2037{
2038 const u32 seed2[5] = {
2039 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2040 0x5b6db6db,
2041 };
2042 u32 r;
2043 r = seed2[(a + (a >= 10)) / 5];
2044 return b ? ~r : r;
2045}
2046
2047static int make_shift(int comp2, int comp5, int x)
2048{
2049 const u8 seed3[32] = {
2050 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2051 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2052 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2053 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2054 };
2055
2056 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2057}
2058
2059static u32 get_etalon(int flip, u32 addr)
2060{
2061 u32 mask_byte = 0;
2062 int comp1 = (addr >> 1) & 1;
2063 int comp2 = (addr >> 3) & 0x1f;
2064 int comp3 = (addr >> 8) & 0xf;
2065 int comp4 = (addr >> 12) & 0xf;
2066 int comp5 = (addr >> 16) & 0x1f;
2067 u32 mask_bit = ~(0x10001 << comp3);
2068 u32 part1;
2069 u32 part2;
2070 int byte;
2071
2072 part2 =
2073 ((seed1[comp5] >>
2074 make_shift(comp2, comp5,
2075 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2076 part1 =
2077 ((seed1[comp5] >>
2078 make_shift(comp2, comp5,
2079 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2080
2081 for (byte = 0; byte < 4; byte++)
2082 if ((get_seed2(comp5, comp4) >>
2083 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2084 mask_byte |= 0xff << (8 * byte);
2085
2086 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2087 (comp3 + 16));
2088}
2089
2090static void
2091write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2092 char flip)
2093{
2094 int i;
2095 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002096 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2097 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002098}
2099
2100static u8
2101check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2102 char flip)
2103{
2104 u8 failmask = 0;
2105 u32 failxor[2];
2106 int i;
2107 int comp1, comp2, comp3;
2108
2109 failxor[0] = 0;
2110 failxor[1] = 0;
2111
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002112 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002113 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2114 for (comp1 = 0; comp1 < 16; comp1++)
2115 for (comp2 = 0; comp2 < 64; comp2++) {
2116 u32 addr =
2117 (totalrank << 28) | (region << 25) | (block
2118 << 16)
2119 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2120 2);
2121 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002122 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002123 }
2124 for (i = 0; i < 8; i++)
2125 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2126 failmask |= 1 << i;
2127 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002128 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002129 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2130 return failmask;
2131}
2132
2133static int check_bounded(unsigned short *vals, u16 bound)
2134{
2135 int i;
2136
2137 for (i = 0; i < 8; i++)
2138 if (vals[i] < bound)
2139 return 0;
2140 return 1;
2141}
2142
2143enum state {
2144 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2145};
2146
2147static int validate_state(enum state *in)
2148{
2149 int i;
2150 for (i = 0; i < 8; i++)
2151 if (in[i] != COMPLETE)
2152 return 0;
2153 return 1;
2154}
2155
2156static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002157do_fsm(enum state *state, u16 *counter,
2158 u8 fail_mask, int margin, int uplimit,
2159 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002160{
2161 int lane;
2162
2163 for (lane = 0; lane < 8; lane++) {
2164 int is_fail = (fail_mask >> lane) & 1;
2165 switch (state[lane]) {
2166 case BEFORE_USABLE:
2167 if (!is_fail) {
2168 counter[lane] = 1;
2169 state[lane] = AT_USABLE;
2170 break;
2171 }
2172 counter[lane] = 0;
2173 state[lane] = BEFORE_USABLE;
2174 break;
2175 case AT_USABLE:
2176 if (!is_fail) {
2177 ++counter[lane];
2178 if (counter[lane] >= margin) {
2179 state[lane] = AT_MARGIN;
2180 res_low[lane] = val - margin + 1;
2181 break;
2182 }
2183 state[lane] = 1;
2184 break;
2185 }
2186 counter[lane] = 0;
2187 state[lane] = BEFORE_USABLE;
2188 break;
2189 case AT_MARGIN:
2190 if (is_fail) {
2191 state[lane] = COMPLETE;
2192 res_high[lane] = val - 1;
2193 } else {
2194 counter[lane]++;
2195 state[lane] = AT_MARGIN;
2196 if (val == uplimit) {
2197 state[lane] = COMPLETE;
2198 res_high[lane] = uplimit;
2199 }
2200 }
2201 break;
2202 case COMPLETE:
2203 break;
2204 }
2205 }
2206}
2207
2208static void
2209train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2210 u8 total_rank, u8 reg_178, int first_run, int niter,
2211 timing_bounds_t * timings)
2212{
2213 int lane;
2214 enum state state[8];
2215 u16 count[8];
2216 u8 lower_usable[8];
2217 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002218 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002219 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002220 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002221
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002222 for (i = 0; i < 8; i++)
2223 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002224
2225 if (!first_run) {
2226 int is_all_ok = 1;
2227 for (lane = 0; lane < 8; lane++)
2228 if (timings[reg_178][channel][slot][rank][lane].
2229 smallest ==
2230 timings[reg_178][channel][slot][rank][lane].
2231 largest) {
2232 timings[reg_178][channel][slot][rank][lane].
2233 smallest = 0;
2234 timings[reg_178][channel][slot][rank][lane].
2235 largest = 0;
2236 is_all_ok = 0;
2237 }
2238 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002239 for (i = 0; i < 8; i++)
2240 state[i] = COMPLETE;
2241 }
2242 }
2243
2244 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2245 u8 failmask = 0;
2246 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2247 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2248 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002249 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002250 do_fsm(state, count, failmask, 5, 47, lower_usable,
2251 upper_usable, reg1b3);
2252 }
2253
2254 if (reg1b3) {
2255 write_1d0(0, 0x1b3, 6, 1);
2256 write_1d0(0, 0x1a3, 6, 1);
2257 for (lane = 0; lane < 8; lane++) {
2258 if (state[lane] == COMPLETE) {
2259 timings[reg_178][channel][slot][rank][lane].
2260 smallest =
2261 lower_usable[lane] +
2262 (info->training.
2263 lane_timings[0][channel][slot][rank][lane]
2264 & 0x3F) - 32;
2265 timings[reg_178][channel][slot][rank][lane].
2266 largest =
2267 upper_usable[lane] +
2268 (info->training.
2269 lane_timings[0][channel][slot][rank][lane]
2270 & 0x3F) - 32;
2271 }
2272 }
2273 }
2274
2275 if (!first_run) {
2276 for (lane = 0; lane < 8; lane++)
2277 if (state[lane] == COMPLETE) {
2278 write_500(info, channel,
2279 timings[reg_178][channel][slot][rank]
2280 [lane].smallest,
2281 get_timing_register_addr(lane, 0,
2282 slot, rank),
2283 9, 1);
2284 write_500(info, channel,
2285 timings[reg_178][channel][slot][rank]
2286 [lane].smallest +
2287 info->training.
2288 lane_timings[1][channel][slot][rank]
2289 [lane]
2290 -
2291 info->training.
2292 lane_timings[0][channel][slot][rank]
2293 [lane], get_timing_register_addr(lane,
2294 1,
2295 slot,
2296 rank),
2297 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002298 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002299 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002300 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002301
2302 do {
2303 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002304 for (i = 0; i < niter; i++) {
2305 if (failmask == 0xFF)
2306 break;
2307 failmask |=
2308 check_testing_type2(info, total_rank, 2, i,
2309 0);
2310 failmask |=
2311 check_testing_type2(info, total_rank, 3, i,
2312 1);
2313 }
Felix Held04be2dd2018-07-29 04:53:22 +02002314 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002315 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002316 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002317 if ((1 << lane) & failmask) {
2318 if (timings[reg_178][channel]
2319 [slot][rank][lane].
2320 largest <=
2321 timings[reg_178][channel]
2322 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002323 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002324 [lane] = -1;
2325 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002326 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002327 [lane] = 0;
2328 timings[reg_178]
2329 [channel][slot]
2330 [rank][lane].
2331 smallest++;
2332 write_500(info, channel,
2333 timings
2334 [reg_178]
2335 [channel]
2336 [slot][rank]
2337 [lane].
2338 smallest,
2339 get_timing_register_addr
2340 (lane, 0,
2341 slot, rank),
2342 9, 1);
2343 write_500(info, channel,
2344 timings
2345 [reg_178]
2346 [channel]
2347 [slot][rank]
2348 [lane].
2349 smallest +
2350 info->
2351 training.
2352 lane_timings
2353 [1][channel]
2354 [slot][rank]
2355 [lane]
2356 -
2357 info->
2358 training.
2359 lane_timings
2360 [0][channel]
2361 [slot][rank]
2362 [lane],
2363 get_timing_register_addr
2364 (lane, 1,
2365 slot, rank),
2366 9, 1);
2367 }
2368 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002369 num_successfully_checked[lane]
2370 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002371 }
2372 }
Felix Held04be2dd2018-07-29 04:53:22 +02002373 while (!check_bounded(num_successfully_checked, 2))
2374 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002375
2376 for (lane = 0; lane < 8; lane++)
2377 if (state[lane] == COMPLETE) {
2378 write_500(info, channel,
2379 timings[reg_178][channel][slot][rank]
2380 [lane].largest,
2381 get_timing_register_addr(lane, 0,
2382 slot, rank),
2383 9, 1);
2384 write_500(info, channel,
2385 timings[reg_178][channel][slot][rank]
2386 [lane].largest +
2387 info->training.
2388 lane_timings[1][channel][slot][rank]
2389 [lane]
2390 -
2391 info->training.
2392 lane_timings[0][channel][slot][rank]
2393 [lane], get_timing_register_addr(lane,
2394 1,
2395 slot,
2396 rank),
2397 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002398 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002400 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002401
2402 do {
2403 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002404 for (i = 0; i < niter; i++) {
2405 if (failmask == 0xFF)
2406 break;
2407 failmask |=
2408 check_testing_type2(info, total_rank, 2, i,
2409 0);
2410 failmask |=
2411 check_testing_type2(info, total_rank, 3, i,
2412 1);
2413 }
2414
Felix Held04be2dd2018-07-29 04:53:22 +02002415 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002416 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002417 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002418 if ((1 << lane) & failmask) {
2419 if (timings[reg_178][channel]
2420 [slot][rank][lane].
2421 largest <=
2422 timings[reg_178][channel]
2423 [slot][rank][lane].
2424 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002425 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002426 [lane] = -1;
2427 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002428 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002429 [lane] = 0;
2430 timings[reg_178]
2431 [channel][slot]
2432 [rank][lane].
2433 largest--;
2434 write_500(info, channel,
2435 timings
2436 [reg_178]
2437 [channel]
2438 [slot][rank]
2439 [lane].
2440 largest,
2441 get_timing_register_addr
2442 (lane, 0,
2443 slot, rank),
2444 9, 1);
2445 write_500(info, channel,
2446 timings
2447 [reg_178]
2448 [channel]
2449 [slot][rank]
2450 [lane].
2451 largest +
2452 info->
2453 training.
2454 lane_timings
2455 [1][channel]
2456 [slot][rank]
2457 [lane]
2458 -
2459 info->
2460 training.
2461 lane_timings
2462 [0][channel]
2463 [slot][rank]
2464 [lane],
2465 get_timing_register_addr
2466 (lane, 1,
2467 slot, rank),
2468 9, 1);
2469 }
2470 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002471 num_successfully_checked[lane]
2472 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002473 }
2474 }
2475 }
Felix Held04be2dd2018-07-29 04:53:22 +02002476 while (!check_bounded(num_successfully_checked, 3))
2477 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002478
2479 for (lane = 0; lane < 8; lane++) {
2480 write_500(info, channel,
2481 info->training.
2482 lane_timings[0][channel][slot][rank][lane],
2483 get_timing_register_addr(lane, 0, slot, rank),
2484 9, 1);
2485 write_500(info, channel,
2486 info->training.
2487 lane_timings[1][channel][slot][rank][lane],
2488 get_timing_register_addr(lane, 1, slot, rank),
2489 9, 1);
2490 if (timings[reg_178][channel][slot][rank][lane].
2491 largest <=
2492 timings[reg_178][channel][slot][rank][lane].
2493 smallest) {
2494 timings[reg_178][channel][slot][rank][lane].
2495 largest = 0;
2496 timings[reg_178][channel][slot][rank][lane].
2497 smallest = 0;
2498 }
2499 }
2500 }
2501}
2502
2503static void set_10b(struct raminfo *info, u8 val)
2504{
2505 int channel;
2506 int slot, rank;
2507 int lane;
2508
2509 if (read_1d0(0x10b, 6) == val)
2510 return;
2511
2512 write_1d0(val, 0x10b, 6, 1);
2513
2514 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2515 u16 reg_500;
2516 reg_500 = read_500(info, channel,
2517 get_timing_register_addr(lane, 0, slot,
2518 rank), 9);
2519 if (val == 1) {
2520 if (lut16[info->clock_speed_index] <= reg_500)
2521 reg_500 -= lut16[info->clock_speed_index];
2522 else
2523 reg_500 = 0;
2524 } else {
2525 reg_500 += lut16[info->clock_speed_index];
2526 }
2527 write_500(info, channel, reg_500,
2528 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2529 }
2530}
2531
2532static void set_ecc(int onoff)
2533{
2534 int channel;
2535 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2536 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002537 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002538 if (onoff)
2539 t |= 1;
2540 else
2541 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002542 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002543 }
2544}
2545
2546static void set_178(u8 val)
2547{
2548 if (val >= 31)
2549 val = val - 31;
2550 else
2551 val = 63 - val;
2552
2553 write_1d0(2 * val, 0x178, 7, 1);
2554}
2555
2556static void
2557write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2558 int type)
2559{
2560 int lane;
2561
2562 for (lane = 0; lane < 8; lane++)
2563 write_500(info, channel,
2564 info->training.
2565 lane_timings[type][channel][slot][rank][lane],
2566 get_timing_register_addr(lane, type, slot, rank), 9,
2567 0);
2568}
2569
2570static void
2571try_timing_offsets(struct raminfo *info, int channel,
2572 int slot, int rank, int totalrank)
2573{
2574 u16 count[8];
2575 enum state state[8];
2576 u8 lower_usable[8], upper_usable[8];
2577 int lane;
2578 int i;
2579 int flip = 1;
2580 int timing_offset;
2581
2582 for (i = 0; i < 8; i++)
2583 state[i] = BEFORE_USABLE;
2584
2585 memset(count, 0, sizeof(count));
2586
2587 for (lane = 0; lane < 8; lane++)
2588 write_500(info, channel,
2589 info->training.
2590 lane_timings[2][channel][slot][rank][lane] + 32,
2591 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2592
2593 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2594 timing_offset++) {
2595 u8 failmask;
2596 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2597 failmask = 0;
2598 for (i = 0; i < 2 && failmask != 0xff; i++) {
2599 flip = !flip;
2600 write_testing(info, totalrank, flip);
2601 failmask |= check_testing(info, totalrank, flip);
2602 }
2603 do_fsm(state, count, failmask, 10, 63, lower_usable,
2604 upper_usable, timing_offset);
2605 }
2606 write_1d0(0, 0x1bb, 6, 1);
2607 dump_timings(info);
2608 if (!validate_state(state))
2609 die("Couldn't discover DRAM timings (1)\n");
2610
2611 for (lane = 0; lane < 8; lane++) {
2612 u8 bias = 0;
2613
2614 if (info->silicon_revision) {
2615 int usable_length;
2616
2617 usable_length = upper_usable[lane] - lower_usable[lane];
2618 if (usable_length >= 20) {
2619 bias = usable_length / 2 - 10;
2620 if (bias >= 2)
2621 bias = 2;
2622 }
2623 }
2624 write_500(info, channel,
2625 info->training.
2626 lane_timings[2][channel][slot][rank][lane] +
2627 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2628 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2629 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2630 info->training.lane_timings[2][channel][slot][rank][lane] +
2631 lower_usable[lane];
2632 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2633 info->training.lane_timings[2][channel][slot][rank][lane] +
2634 upper_usable[lane];
2635 info->training.timing2_offset[channel][slot][rank][lane] =
2636 info->training.lane_timings[2][channel][slot][rank][lane];
2637 }
2638}
2639
2640static u8
2641choose_training(struct raminfo *info, int channel, int slot, int rank,
2642 int lane, timing_bounds_t * timings, u8 center_178)
2643{
2644 u16 central_weight;
2645 u16 side_weight;
2646 unsigned int sum = 0, count = 0;
2647 u8 span;
2648 u8 lower_margin, upper_margin;
2649 u8 reg_178;
2650 u8 result;
2651
2652 span = 12;
2653 central_weight = 20;
2654 side_weight = 20;
2655 if (info->silicon_revision == 1 && channel == 1) {
2656 central_weight = 5;
2657 side_weight = 20;
2658 if ((info->
2659 populated_ranks_mask[1] ^ (info->
2660 populated_ranks_mask[1] >> 2)) &
2661 1)
2662 span = 18;
2663 }
2664 if ((info->populated_ranks_mask[0] & 5) == 5) {
2665 central_weight = 20;
2666 side_weight = 20;
2667 }
2668 if (info->clock_speed_index >= 2
2669 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2670 if (info->silicon_revision == 1) {
2671 switch (channel) {
2672 case 0:
2673 if (lane == 1) {
2674 central_weight = 10;
2675 side_weight = 20;
2676 }
2677 break;
2678 case 1:
2679 if (lane == 6) {
2680 side_weight = 5;
2681 central_weight = 20;
2682 }
2683 break;
2684 }
2685 }
2686 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2687 side_weight = 5;
2688 central_weight = 20;
2689 }
2690 }
2691 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2692 reg_178 += span) {
2693 u8 smallest;
2694 u8 largest;
2695 largest = timings[reg_178][channel][slot][rank][lane].largest;
2696 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2697 if (largest - smallest + 1 >= 5) {
2698 unsigned int weight;
2699 if (reg_178 == center_178)
2700 weight = central_weight;
2701 else
2702 weight = side_weight;
2703 sum += weight * (largest + smallest);
2704 count += weight;
2705 }
2706 }
2707 dump_timings(info);
2708 if (count == 0)
2709 die("Couldn't discover DRAM timings (2)\n");
2710 result = sum / (2 * count);
2711 lower_margin =
2712 result - timings[center_178][channel][slot][rank][lane].smallest;
2713 upper_margin =
2714 timings[center_178][channel][slot][rank][lane].largest - result;
2715 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002716 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002717 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002718 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002719 return result;
2720}
2721
2722#define STANDARD_MIN_MARGIN 5
2723
2724static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2725{
2726 u16 margin[64];
2727 int lane, rank, slot, channel;
2728 u8 reg178;
2729 int count = 0, sum = 0;
2730
2731 for (reg178 = reg178_min[info->clock_speed_index];
2732 reg178 < reg178_max[info->clock_speed_index];
2733 reg178 += reg178_step[info->clock_speed_index]) {
2734 margin[reg178] = -1;
2735 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2736 int curmargin =
2737 timings[reg178][channel][slot][rank][lane].largest -
2738 timings[reg178][channel][slot][rank][lane].
2739 smallest + 1;
2740 if (curmargin < margin[reg178])
2741 margin[reg178] = curmargin;
2742 }
2743 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2744 u16 weight;
2745 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2746 sum += weight * reg178;
2747 count += weight;
2748 }
2749 }
2750 dump_timings(info);
2751 if (count == 0)
2752 die("Couldn't discover DRAM timings (3)\n");
2753
2754 u8 threshold;
2755
2756 for (threshold = 30; threshold >= 5; threshold--) {
2757 int usable_length = 0;
2758 int smallest_fount = 0;
2759 for (reg178 = reg178_min[info->clock_speed_index];
2760 reg178 < reg178_max[info->clock_speed_index];
2761 reg178 += reg178_step[info->clock_speed_index])
2762 if (margin[reg178] >= threshold) {
2763 usable_length +=
2764 reg178_step[info->clock_speed_index];
2765 info->training.reg178_largest =
2766 reg178 -
2767 2 * reg178_step[info->clock_speed_index];
2768
2769 if (!smallest_fount) {
2770 smallest_fount = 1;
2771 info->training.reg178_smallest =
2772 reg178 +
2773 reg178_step[info->
2774 clock_speed_index];
2775 }
2776 }
2777 if (usable_length >= 0x21)
2778 break;
2779 }
2780
2781 return sum / count;
2782}
2783
2784static int check_cached_sanity(struct raminfo *info)
2785{
2786 int lane;
2787 int slot, rank;
2788 int channel;
2789
2790 if (!info->cached_training)
2791 return 0;
2792
2793 for (channel = 0; channel < NUM_CHANNELS; channel++)
2794 for (slot = 0; slot < NUM_SLOTS; slot++)
2795 for (rank = 0; rank < NUM_RANKS; rank++)
2796 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2797 u16 cached_value, estimation_value;
2798 cached_value =
2799 info->cached_training->
2800 lane_timings[1][channel][slot][rank]
2801 [lane];
2802 if (cached_value >= 0x18
2803 && cached_value <= 0x1E7) {
2804 estimation_value =
2805 info->training.
2806 lane_timings[1][channel]
2807 [slot][rank][lane];
2808 if (estimation_value <
2809 cached_value - 24)
2810 return 0;
2811 if (estimation_value >
2812 cached_value + 24)
2813 return 0;
2814 }
2815 }
2816 return 1;
2817}
2818
2819static int try_cached_training(struct raminfo *info)
2820{
2821 u8 saved_243[2];
2822 u8 tm;
2823
2824 int channel, slot, rank, lane;
2825 int flip = 1;
2826 int i, j;
2827
2828 if (!check_cached_sanity(info))
2829 return 0;
2830
2831 info->training.reg178_center = info->cached_training->reg178_center;
2832 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2833 info->training.reg178_largest = info->cached_training->reg178_largest;
2834 memcpy(&info->training.timing_bounds,
2835 &info->cached_training->timing_bounds,
2836 sizeof(info->training.timing_bounds));
2837 memcpy(&info->training.timing_offset,
2838 &info->cached_training->timing_offset,
2839 sizeof(info->training.timing_offset));
2840
2841 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002842 saved_243[0] = MCHBAR8(0x243);
2843 saved_243[1] = MCHBAR8(0x643);
2844 MCHBAR8(0x243) = saved_243[0] | 2;
2845 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002846 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002847 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002848 if (read_1d0(0x10b, 6) & 1)
2849 set_10b(info, 0);
2850 for (tm = 0; tm < 2; tm++) {
2851 int totalrank;
2852
2853 set_178(tm ? info->cached_training->reg178_largest : info->
2854 cached_training->reg178_smallest);
2855
2856 totalrank = 0;
2857 /* Check timing ranges. With i == 0 we check smallest one and with
2858 i == 1 the largest bound. With j == 0 we check that on the bound
2859 it still works whereas with j == 1 we check that just outside of
2860 bound we fail.
2861 */
2862 FOR_POPULATED_RANKS_BACKWARDS {
2863 for (i = 0; i < 2; i++) {
2864 for (lane = 0; lane < 8; lane++) {
2865 write_500(info, channel,
2866 info->cached_training->
2867 timing2_bounds[channel][slot]
2868 [rank][lane][i],
2869 get_timing_register_addr(lane,
2870 3,
2871 slot,
2872 rank),
2873 9, 1);
2874
2875 if (!i)
2876 write_500(info, channel,
2877 info->
2878 cached_training->
2879 timing2_offset
2880 [channel][slot][rank]
2881 [lane],
2882 get_timing_register_addr
2883 (lane, 2, slot, rank),
2884 9, 1);
2885 write_500(info, channel,
2886 i ? info->cached_training->
2887 timing_bounds[tm][channel]
2888 [slot][rank][lane].
2889 largest : info->
2890 cached_training->
2891 timing_bounds[tm][channel]
2892 [slot][rank][lane].smallest,
2893 get_timing_register_addr(lane,
2894 0,
2895 slot,
2896 rank),
2897 9, 1);
2898 write_500(info, channel,
2899 info->cached_training->
2900 timing_offset[channel][slot]
2901 [rank][lane] +
2902 (i ? info->cached_training->
2903 timing_bounds[tm][channel]
2904 [slot][rank][lane].
2905 largest : info->
2906 cached_training->
2907 timing_bounds[tm][channel]
2908 [slot][rank][lane].
2909 smallest) - 64,
2910 get_timing_register_addr(lane,
2911 1,
2912 slot,
2913 rank),
2914 9, 1);
2915 }
2916 for (j = 0; j < 2; j++) {
2917 u8 failmask;
2918 u8 expected_failmask;
2919 char reg1b3;
2920
2921 reg1b3 = (j == 1) + 4;
2922 reg1b3 =
2923 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2924 write_1d0(reg1b3, 0x1bb, 6, 1);
2925 write_1d0(reg1b3, 0x1b3, 6, 1);
2926 write_1d0(reg1b3, 0x1a3, 6, 1);
2927
2928 flip = !flip;
2929 write_testing(info, totalrank, flip);
2930 failmask =
2931 check_testing(info, totalrank,
2932 flip);
2933 expected_failmask =
2934 j == 0 ? 0x00 : 0xff;
2935 if (failmask != expected_failmask)
2936 goto fail;
2937 }
2938 }
2939 totalrank++;
2940 }
2941 }
2942
2943 set_178(info->cached_training->reg178_center);
2944 if (info->use_ecc)
2945 set_ecc(1);
2946 write_training_data(info);
2947 write_1d0(0, 322, 3, 1);
2948 info->training = *info->cached_training;
2949
2950 write_1d0(0, 0x1bb, 6, 1);
2951 write_1d0(0, 0x1b3, 6, 1);
2952 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002953 MCHBAR8(0x243) = saved_243[0];
2954 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002955
2956 return 1;
2957
2958fail:
2959 FOR_POPULATED_RANKS {
2960 write_500_timings_type(info, channel, slot, rank, 1);
2961 write_500_timings_type(info, channel, slot, rank, 2);
2962 write_500_timings_type(info, channel, slot, rank, 3);
2963 }
2964
2965 write_1d0(0, 0x1bb, 6, 1);
2966 write_1d0(0, 0x1b3, 6, 1);
2967 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002968 MCHBAR8(0x243) = saved_243[0];
2969 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002970
2971 return 0;
2972}
2973
2974static void do_ram_training(struct raminfo *info)
2975{
2976 u8 saved_243[2];
2977 int totalrank = 0;
2978 u8 reg_178;
2979 int niter;
2980
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002981 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002982 int lane, rank, slot, channel;
2983 u8 reg178_center;
2984
2985 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002986 saved_243[0] = MCHBAR8(0x243);
2987 saved_243[1] = MCHBAR8(0x643);
2988 MCHBAR8(0x243) = saved_243[0] | 2;
2989 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002990 switch (info->clock_speed_index) {
2991 case 0:
2992 niter = 5;
2993 break;
2994 case 1:
2995 niter = 10;
2996 break;
2997 default:
2998 niter = 19;
2999 break;
3000 }
3001 set_ecc(0);
3002
3003 FOR_POPULATED_RANKS_BACKWARDS {
3004 int i;
3005
3006 write_500_timings_type(info, channel, slot, rank, 0);
3007
3008 write_testing(info, totalrank, 0);
3009 for (i = 0; i < niter; i++) {
3010 write_testing_type2(info, totalrank, 2, i, 0);
3011 write_testing_type2(info, totalrank, 3, i, 1);
3012 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003013 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003014 totalrank++;
3015 }
3016
3017 if (reg178_min[info->clock_speed_index] <
3018 reg178_max[info->clock_speed_index])
3019 memset(timings[reg178_min[info->clock_speed_index]], 0,
3020 sizeof(timings[0]) *
3021 (reg178_max[info->clock_speed_index] -
3022 reg178_min[info->clock_speed_index]));
3023 for (reg_178 = reg178_min[info->clock_speed_index];
3024 reg_178 < reg178_max[info->clock_speed_index];
3025 reg_178 += reg178_step[info->clock_speed_index]) {
3026 totalrank = 0;
3027 set_178(reg_178);
3028 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3029 for (slot = 0; slot < NUM_SLOTS; slot++)
3030 for (rank = 0; rank < NUM_RANKS; rank++) {
3031 memset(&timings[reg_178][channel][slot]
3032 [rank][0].smallest, 0, 16);
3033 if (info->
3034 populated_ranks[channel][slot]
3035 [rank]) {
3036 train_ram_at_178(info, channel,
3037 slot, rank,
3038 totalrank,
3039 reg_178, 1,
3040 niter,
3041 timings);
3042 totalrank++;
3043 }
3044 }
3045 }
3046
3047 reg178_center = choose_reg178(info, timings);
3048
3049 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3050 info->training.timing_bounds[0][channel][slot][rank][lane].
3051 smallest =
3052 timings[info->training.
3053 reg178_smallest][channel][slot][rank][lane].
3054 smallest;
3055 info->training.timing_bounds[0][channel][slot][rank][lane].
3056 largest =
3057 timings[info->training.
3058 reg178_smallest][channel][slot][rank][lane].largest;
3059 info->training.timing_bounds[1][channel][slot][rank][lane].
3060 smallest =
3061 timings[info->training.
3062 reg178_largest][channel][slot][rank][lane].smallest;
3063 info->training.timing_bounds[1][channel][slot][rank][lane].
3064 largest =
3065 timings[info->training.
3066 reg178_largest][channel][slot][rank][lane].largest;
3067 info->training.timing_offset[channel][slot][rank][lane] =
3068 info->training.lane_timings[1][channel][slot][rank][lane]
3069 -
3070 info->training.lane_timings[0][channel][slot][rank][lane] +
3071 64;
3072 }
3073
3074 if (info->silicon_revision == 1
3075 && (info->
3076 populated_ranks_mask[1] ^ (info->
3077 populated_ranks_mask[1] >> 2)) & 1) {
3078 int ranks_after_channel1;
3079
3080 totalrank = 0;
3081 for (reg_178 = reg178_center - 18;
3082 reg_178 <= reg178_center + 18; reg_178 += 18) {
3083 totalrank = 0;
3084 set_178(reg_178);
3085 for (slot = 0; slot < NUM_SLOTS; slot++)
3086 for (rank = 0; rank < NUM_RANKS; rank++) {
3087 if (info->
3088 populated_ranks[1][slot][rank]) {
3089 train_ram_at_178(info, 1, slot,
3090 rank,
3091 totalrank,
3092 reg_178, 0,
3093 niter,
3094 timings);
3095 totalrank++;
3096 }
3097 }
3098 }
3099 ranks_after_channel1 = totalrank;
3100
3101 for (reg_178 = reg178_center - 12;
3102 reg_178 <= reg178_center + 12; reg_178 += 12) {
3103 totalrank = ranks_after_channel1;
3104 set_178(reg_178);
3105 for (slot = 0; slot < NUM_SLOTS; slot++)
3106 for (rank = 0; rank < NUM_RANKS; rank++)
3107 if (info->
3108 populated_ranks[0][slot][rank]) {
3109 train_ram_at_178(info, 0, slot,
3110 rank,
3111 totalrank,
3112 reg_178, 0,
3113 niter,
3114 timings);
3115 totalrank++;
3116 }
3117
3118 }
3119 } else {
3120 for (reg_178 = reg178_center - 12;
3121 reg_178 <= reg178_center + 12; reg_178 += 12) {
3122 totalrank = 0;
3123 set_178(reg_178);
3124 FOR_POPULATED_RANKS_BACKWARDS {
3125 train_ram_at_178(info, channel, slot, rank,
3126 totalrank, reg_178, 0, niter,
3127 timings);
3128 totalrank++;
3129 }
3130 }
3131 }
3132
3133 set_178(reg178_center);
3134 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3135 u16 tm0;
3136
3137 tm0 =
3138 choose_training(info, channel, slot, rank, lane, timings,
3139 reg178_center);
3140 write_500(info, channel, tm0,
3141 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3142 write_500(info, channel,
3143 tm0 +
3144 info->training.
3145 lane_timings[1][channel][slot][rank][lane] -
3146 info->training.
3147 lane_timings[0][channel][slot][rank][lane],
3148 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3149 }
3150
3151 totalrank = 0;
3152 FOR_POPULATED_RANKS_BACKWARDS {
3153 try_timing_offsets(info, channel, slot, rank, totalrank);
3154 totalrank++;
3155 }
Felix Held04be2dd2018-07-29 04:53:22 +02003156 MCHBAR8(0x243) = saved_243[0];
3157 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003158 write_1d0(0, 0x142, 3, 1);
3159 info->training.reg178_center = reg178_center;
3160}
3161
3162static void ram_training(struct raminfo *info)
3163{
3164 u16 saved_fc4;
3165
Felix Held04be2dd2018-07-29 04:53:22 +02003166 saved_fc4 = MCHBAR16(0xfc4);
3167 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003168
3169 if (info->revision >= 8)
3170 read_4090(info);
3171
3172 if (!try_cached_training(info))
3173 do_ram_training(info);
3174 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3175 && info->clock_speed_index < 2)
3176 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003177 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003178}
3179
Martin Roth468d02c2019-10-23 21:44:42 -06003180static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003181{
Martin Roth468d02c2019-10-23 21:44:42 -06003182 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003183 if (a > b) {
3184 t = a;
3185 a = b;
3186 b = t;
3187 }
3188 /* invariant a < b. */
3189 while (a) {
3190 t = b % a;
3191 b = a;
3192 a = t;
3193 }
3194 return b;
3195}
3196
3197static inline int div_roundup(int a, int b)
3198{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003199 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003200}
3201
Martin Roth468d02c2019-10-23 21:44:42 -06003202static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003203{
3204 return (a * b) / gcd(a, b);
3205}
3206
3207struct stru1 {
3208 u8 freqs_reversed;
3209 u8 freq_diff_reduced;
3210 u8 freq_min_reduced;
3211 u8 divisor_f4_to_fmax;
3212 u8 divisor_f3_to_fmax;
3213 u8 freq4_to_max_remainder;
3214 u8 freq3_to_2_remainder;
3215 u8 freq3_to_2_remaindera;
3216 u8 freq4_to_2_remainder;
3217 int divisor_f3_to_f1, divisor_f4_to_f2;
3218 int common_time_unit_ps;
3219 int freq_max_reduced;
3220};
3221
3222static void
3223compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3224 int num_cycles_2, int num_cycles_1, int round_it,
3225 int add_freqs, struct stru1 *result)
3226{
3227 int g;
3228 int common_time_unit_ps;
3229 int freq1_reduced, freq2_reduced;
3230 int freq_min_reduced;
3231 int freq_max_reduced;
3232 int freq3, freq4;
3233
3234 g = gcd(freq1, freq2);
3235 freq1_reduced = freq1 / g;
3236 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003237 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3238 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003239
3240 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3241 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3242 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3243 if (add_freqs) {
3244 freq3 += freq2_reduced;
3245 freq4 += freq1_reduced;
3246 }
3247
3248 if (round_it) {
3249 result->freq3_to_2_remainder = 0;
3250 result->freq3_to_2_remaindera = 0;
3251 result->freq4_to_max_remainder = 0;
3252 result->divisor_f4_to_f2 = 0;
3253 result->divisor_f3_to_f1 = 0;
3254 } else {
3255 if (freq2_reduced < freq1_reduced) {
3256 result->freq3_to_2_remainder =
3257 result->freq3_to_2_remaindera =
3258 freq3 % freq1_reduced - freq1_reduced + 1;
3259 result->freq4_to_max_remainder =
3260 -(freq4 % freq1_reduced);
3261 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3262 result->divisor_f4_to_f2 =
3263 (freq4 -
3264 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3265 result->freq4_to_2_remainder =
3266 -(char)((freq1_reduced - freq2_reduced) +
3267 ((u8) freq4 -
3268 (freq1_reduced -
3269 freq2_reduced)) % (u8) freq2_reduced);
3270 } else {
3271 if (freq2_reduced > freq1_reduced) {
3272 result->freq4_to_max_remainder =
3273 (freq4 % freq2_reduced) - freq2_reduced + 1;
3274 result->freq4_to_2_remainder =
3275 freq4 % freq_max_reduced -
3276 freq_max_reduced + 1;
3277 } else {
3278 result->freq4_to_max_remainder =
3279 -(freq4 % freq2_reduced);
3280 result->freq4_to_2_remainder =
3281 -(char)(freq4 % freq_max_reduced);
3282 }
3283 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3284 result->divisor_f3_to_f1 =
3285 (freq3 -
3286 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3287 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3288 result->freq3_to_2_remaindera =
3289 -(char)((freq_max_reduced - freq_min_reduced) +
3290 (freq3 -
3291 (freq_max_reduced -
3292 freq_min_reduced)) % freq1_reduced);
3293 }
3294 }
3295 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3296 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3297 if (round_it) {
3298 if (freq2_reduced > freq1_reduced) {
3299 if (freq3 % freq_max_reduced)
3300 result->divisor_f3_to_fmax++;
3301 }
3302 if (freq2_reduced < freq1_reduced) {
3303 if (freq4 % freq_max_reduced)
3304 result->divisor_f4_to_fmax++;
3305 }
3306 }
3307 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3308 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3309 result->freq_min_reduced = freq_min_reduced;
3310 result->common_time_unit_ps = common_time_unit_ps;
3311 result->freq_max_reduced = freq_max_reduced;
3312}
3313
3314static void
3315set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3316 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3317 int num_cycles_4, int reverse)
3318{
3319 struct stru1 vv;
3320 char multiplier;
3321
3322 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3323 0, 1, &vv);
3324
3325 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003326 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003327 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3328 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3329 div_roundup(num_cycles_1,
3330 vv.common_time_unit_ps) +
3331 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3332 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3333
3334 u32 y =
3335 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3336 vv.freq_max_reduced * multiplier)
3337 | (vv.
3338 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3339 multiplier) << 16) | ((u8) (vv.
3340 freq_min_reduced
3341 *
3342 multiplier)
3343 << 24);
3344 u32 x =
3345 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3346 divisor_f3_to_f1
3347 << 16)
3348 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3349 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003350 MCHBAR32(reg) = y;
3351 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003352 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003353 MCHBAR32(reg + 4) = y;
3354 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003355 }
3356}
3357
3358static void
3359set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3360 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3361 int num_cycles_4)
3362{
3363 struct stru1 ratios1;
3364 struct stru1 ratios2;
3365
3366 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3367 0, 1, &ratios2);
3368 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3369 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003370 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003371 ratios1.freq4_to_max_remainder | (ratios2.
3372 freq4_to_max_remainder
3373 << 8)
3374 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3375 divisor_f4_to_fmax
3376 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003377 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3378 (ratios2.freq4_to_max_remainder << 8) |
3379 (ratios1.divisor_f4_to_fmax << 16) |
3380 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003381}
3382
3383static void
3384set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3385 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3386{
3387 struct stru1 ratios;
3388
3389 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3390 round_it, add_freqs, &ratios);
3391 switch (mode) {
3392 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003393 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3394 (ratios.freqs_reversed << 8);
3395 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3396 (ratios.freq4_to_max_remainder << 8) |
3397 (ratios.divisor_f3_to_fmax << 16) |
3398 (ratios.divisor_f4_to_fmax << 20) |
3399 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003400 break;
3401
3402 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003403 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3404 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003405 break;
3406
3407 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003408 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3409 (ratios.freq4_to_max_remainder << 8) |
3410 (ratios.divisor_f3_to_fmax << 16) |
3411 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003412 break;
3413
3414 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003415 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3416 (ratios.divisor_f4_to_fmax << 8) |
3417 (ratios.freqs_reversed << 12) |
3418 (ratios.freq_min_reduced << 16) |
3419 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003420 break;
3421 }
3422}
3423
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003424static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003425{
3426 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3427 0, 1);
3428 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3429 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3430 1);
3431 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3432 frequency_11(info), 1231, 1524, 0, 1);
3433 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3434 frequency_11(info) / 2, 1278, 2008, 0, 1);
3435 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3436 1167, 1539, 0, 1);
3437 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3438 frequency_11(info) / 2, 1403, 1318, 0, 1);
3439 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3440 1);
3441 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3442 1);
3443 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3444 1, 1);
3445 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3446 1);
3447 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3448 frequency_11(info) / 2, 4000, 0, 0, 0);
3449 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3450 frequency_11(info) / 2, 4000, 4000, 0, 0);
3451
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003452 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003453 printk(RAM_SPEW, "[6dc] <= %x\n",
3454 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003455 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003456 } else
3457 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3458 info->delay46_ps[0], 0,
3459 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003460 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3461 frequency_11(info), 2500, 0, 0, 0);
3462 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3463 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003464 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003465 printk(RAM_SPEW, "[6e8] <= %x\n",
3466 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003467 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003468 } else
3469 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3470 info->delay46_ps[1], 0,
3471 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003472 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3473 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3474 470, 0);
3475 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3476 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3477 454, 459, 0);
3478 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3479 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3480 2588, 0);
3481 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3482 2405, 0);
3483 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3484 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3485 480, 0);
3486 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003487 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3488 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003489}
3490
3491static u16 get_max_timing(struct raminfo *info, int channel)
3492{
3493 int slot, rank, lane;
3494 u16 ret = 0;
3495
Felix Held04be2dd2018-07-29 04:53:22 +02003496 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003497 return 384;
3498
3499 if (info->revision < 8)
3500 return 256;
3501
3502 for (slot = 0; slot < NUM_SLOTS; slot++)
3503 for (rank = 0; rank < NUM_RANKS; rank++)
3504 if (info->populated_ranks[channel][slot][rank])
3505 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003506 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003507 get_timing_register_addr
3508 (lane, 0, slot,
3509 rank), 9));
3510 return ret;
3511}
3512
3513static void set_274265(struct raminfo *info)
3514{
3515 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3516 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3517 int delay_e_over_cycle_ps;
3518 int cycletime_ps;
3519 int channel;
3520
3521 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003522 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003523 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3524 cycletime_ps =
3525 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3526 delay_d_ps =
3527 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3528 - info->some_delay_3_ps_rounded + 200;
3529 if (!
3530 ((info->silicon_revision == 0
3531 || info->silicon_revision == 1)
3532 && (info->revision >= 8)))
3533 delay_d_ps += halfcycle_ps(info) * 2;
3534 delay_d_ps +=
3535 halfcycle_ps(info) * (!info->revision_flag_1 +
3536 info->some_delay_2_halfcycles_ceil +
3537 2 * info->some_delay_1_cycle_floor +
3538 info->clock_speed_index +
3539 2 * info->cas_latency - 7 + 11);
3540 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3541
Felix Held04be2dd2018-07-29 04:53:22 +02003542 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3543 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3544 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003545 delay_d_ps += 650;
3546 delay_c_ps = delay_d_ps + 1800;
3547 if (delay_c_ps <= delay_a_ps)
3548 delay_e_ps = 0;
3549 else
3550 delay_e_ps =
3551 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3552 cycletime_ps);
3553
3554 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3555 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3556 delay_f_cycles =
3557 div_roundup(2500 - delay_e_over_cycle_ps,
3558 2 * halfcycle_ps(info));
3559 if (delay_f_cycles > delay_e_cycles) {
3560 info->delay46_ps[channel] = delay_e_ps;
3561 delay_e_cycles = 0;
3562 } else {
3563 info->delay46_ps[channel] =
3564 delay_e_over_cycle_ps +
3565 2 * halfcycle_ps(info) * delay_f_cycles;
3566 delay_e_cycles -= delay_f_cycles;
3567 }
3568
3569 if (info->delay46_ps[channel] < 2500) {
3570 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003571 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003572 }
3573 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3574 if (delay_b_ps <= delay_a_ps)
3575 delay_b_ps = 0;
3576 else
3577 delay_b_ps -= delay_a_ps;
3578 info->delay54_ps[channel] =
3579 cycletime_ps * div_roundup(delay_b_ps,
3580 cycletime_ps) -
3581 2 * halfcycle_ps(info) * delay_e_cycles;
3582 if (info->delay54_ps[channel] < 2500)
3583 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003584 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003585 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3586 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003587 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003588 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003589 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003590 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3591 4 * halfcycle_ps(info)) - 6;
3592 MCHBAR32((channel << 10) + 0x274) =
3593 info->training.reg274265[channel][1] |
3594 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003595 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003596 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3597 4 * halfcycle_ps(info)) + 1;
3598 MCHBAR16((channel << 10) + 0x265) =
3599 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003600 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003601 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003602 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603 else
Felix Held04be2dd2018-07-29 04:53:22 +02003604 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605}
3606
3607static void restore_274265(struct raminfo *info)
3608{
3609 int channel;
3610
3611 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003612 MCHBAR32((channel << 10) + 0x274) =
3613 (info->cached_training->reg274265[channel][0] << 16) |
3614 info->cached_training->reg274265[channel][1];
3615 MCHBAR16((channel << 10) + 0x265) =
3616 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003618 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003619 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620 else
Felix Held04be2dd2018-07-29 04:53:22 +02003621 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622}
3623
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624static void dmi_setup(void)
3625{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003626 gav(read8(DEFAULT_DMIBAR + 0x254));
3627 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3628 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003629 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003631 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632
3633 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3634 DEFAULT_GPIOBASE | 0x38);
3635 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3636}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003638void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003641 u16 ggc;
3642 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643
Felix Held04be2dd2018-07-29 04:53:22 +02003644 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3646 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003647 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003648 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
3651 dmi_setup();
3652
Felix Held04be2dd2018-07-29 04:53:22 +02003653 MCHBAR16(0x1170) = 0xa880;
3654 MCHBAR8(0x11c1) = 0x1;
3655 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003656 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003658 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3659 /* 0 for 32MB */
3660 gfxsize = 0;
3661 }
3662
3663 ggc = 0xb00 | ((gfxsize + 5) << 4);
3664
Angel Pons16fe1e02020-07-22 16:12:33 +02003665 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666
3667 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003668 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669
3670 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003671 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003672 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003673 MCHBAR16_OR(0x2c30, 0x200);
3674 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003675 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003676 pci_read_config8(GMA, 0x62); // = 0x2
3677 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003678 read8(DEFAULT_RCBA + 0x2318);
3679 write8(DEFAULT_RCBA + 0x2318, 0x47);
3680 read8(DEFAULT_RCBA + 0x2320);
3681 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682 }
3683
Felix Heldf83d80b2018-07-29 05:30:30 +02003684 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685
Angel Pons16fe1e02020-07-22 16:12:33 +02003686 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003687 gav(read32(DEFAULT_RCBA + 0x3428));
3688 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003689}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003691void raminit(const int s3resume, const u8 *spd_addrmap)
3692{
Martin Roth468d02c2019-10-23 21:44:42 -06003693 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003694 int i;
3695 struct raminfo info;
3696 u8 x2ca8;
3697 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003698 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003699
Felix Held04be2dd2018-07-29 04:53:22 +02003700 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003701
3702 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3703
Angel Pons16fe1e02020-07-22 16:12:33 +02003704 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003705
3706 memset(&info, 0x5a, sizeof(info));
3707
3708 info.last_500_command[0] = 0;
3709 info.last_500_command[1] = 0;
3710
3711 info.fsb_frequency = 135 * 2;
3712 info.board_lane_delay[0] = 0x14;
3713 info.board_lane_delay[1] = 0x07;
3714 info.board_lane_delay[2] = 0x07;
3715 info.board_lane_delay[3] = 0x08;
3716 info.board_lane_delay[4] = 0x56;
3717 info.board_lane_delay[5] = 0x04;
3718 info.board_lane_delay[6] = 0x04;
3719 info.board_lane_delay[7] = 0x05;
3720 info.board_lane_delay[8] = 0x10;
3721
3722 info.training.reg_178 = 0;
3723 info.training.reg_10b = 0;
3724
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725 info.memory_reserved_for_heci_mb = 0;
3726
3727 /* before SPD */
3728 timestamp_add_now(101);
3729
Felix Held29a9c072018-07-29 01:34:45 +02003730 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003731 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003732
3733 collect_system_info(&info);
3734
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003735 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3736
3737 info.use_ecc = 1;
3738 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003739 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003740 int v;
3741 int try;
3742 int addr;
3743 const u8 useful_addresses[] = {
3744 DEVICE_TYPE,
3745 MODULE_TYPE,
3746 DENSITY,
3747 RANKS_AND_DQ,
3748 MEMORY_BUS_WIDTH,
3749 TIMEBASE_DIVIDEND,
3750 TIMEBASE_DIVISOR,
3751 CYCLETIME,
3752 CAS_LATENCIES_LSB,
3753 CAS_LATENCIES_MSB,
3754 CAS_LATENCY_TIME,
3755 0x11, 0x12, 0x13, 0x14, 0x15,
3756 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3757 0x1c, 0x1d,
3758 THERMAL_AND_REFRESH,
3759 0x20,
3760 REFERENCE_RAW_CARD_USED,
3761 RANK1_ADDRESS_MAPPING,
3762 0x75, 0x76, 0x77, 0x78,
3763 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3764 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3765 0x85, 0x86, 0x87, 0x88,
3766 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3767 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3768 0x95
3769 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003770 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771 continue;
3772 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003773 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003774 DEVICE_TYPE);
3775 if (v >= 0)
3776 break;
3777 }
3778 if (v < 0)
3779 continue;
3780 for (addr = 0;
3781 addr <
3782 sizeof(useful_addresses) /
3783 sizeof(useful_addresses[0]); addr++)
3784 gav(info.
3785 spd[channel][0][useful_addresses
3786 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003787 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003788 useful_addresses
3789 [addr]));
3790 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3791 die("Only DDR3 is supported");
3792
3793 v = info.spd[channel][0][RANKS_AND_DQ];
3794 info.populated_ranks[channel][0][0] = 1;
3795 info.populated_ranks[channel][0][1] =
3796 ((v >> 3) & 7);
3797 if (((v >> 3) & 7) > 1)
3798 die("At most 2 ranks are supported");
3799 if ((v & 7) == 0 || (v & 7) > 2)
3800 die("Only x8 and x16 modules are supported");
3801 if ((info.
3802 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3803 && (info.
3804 spd[channel][slot][MODULE_TYPE] & 0xF)
3805 != 3)
3806 die("Registered memory is not supported");
3807 info.is_x16_module[channel][0] = (v & 7) - 1;
3808 info.density[channel][slot] =
3809 info.spd[channel][slot][DENSITY] & 0xF;
3810 if (!
3811 (info.
3812 spd[channel][slot][MEMORY_BUS_WIDTH] &
3813 0x18))
3814 info.use_ecc = 0;
3815 }
3816
3817 gav(0x55);
3818
3819 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3820 int v = 0;
3821 for (slot = 0; slot < NUM_SLOTS; slot++)
3822 for (rank = 0; rank < NUM_RANKS; rank++)
3823 v |= info.
3824 populated_ranks[channel][slot][rank]
3825 << (2 * slot + rank);
3826 info.populated_ranks_mask[channel] = v;
3827 }
3828
3829 gav(0x55);
3830
Angel Pons16fe1e02020-07-22 16:12:33 +02003831 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003832 }
3833
3834 /* after SPD */
3835 timestamp_add_now(102);
3836
Felix Held04be2dd2018-07-29 04:53:22 +02003837 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003838
3839 collect_system_info(&info);
3840 calculate_timings(&info);
3841
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003842 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003843 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003844 if (x2ca8 == 0 && (reg8 & 0x80)) {
3845 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3846 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3847 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3848 */
3849
3850 /* Clear bit7. */
3851
3852 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3853 (reg8 & ~(1 << 7)));
3854
3855 printk(BIOS_INFO,
3856 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003857 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003858 }
3859 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003860
3861 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003862 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3863 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003864
3865 compute_derived_timings(&info);
3866
3867 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003868 gav(MCHBAR8(0x164));
3869 MCHBAR8(0x164) = 0x26;
3870 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871 }
3872
Felix Held04be2dd2018-07-29 04:53:22 +02003873 MCHBAR32_OR(0x18b4, 0x210000);
3874 MCHBAR32_OR(0x1890, 0x2000000);
3875 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876
Angel Ponsa457e352020-07-22 18:17:33 +02003877 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3878 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879
Felix Held04be2dd2018-07-29 04:53:22 +02003880 gav(MCHBAR16(0x2c10));
3881 MCHBAR16(0x2c10) = 0x412;
3882 gav(MCHBAR16(0x2c10));
3883 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884
Felix Held04be2dd2018-07-29 04:53:22 +02003885 gav(MCHBAR8(0x2ca8)); // !!!!
3886 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887
Angel Ponsa457e352020-07-22 18:17:33 +02003888 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3889 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003890 gav(MCHBAR32(0x1c04)); // !!!!
3891 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
3893 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003894 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895 }
3896
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR32(0x18d8) = 0x120000;
3898 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003899 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3900 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003901 MCHBAR32(0x18d8) = 0x40000;
3902 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003903 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3904 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003905 MCHBAR32(0x18d8) = 0x180000;
3906 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003907 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3908 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003909 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910
Felix Held04be2dd2018-07-29 04:53:22 +02003911 gav(MCHBAR32(0x18dc)); // !!!!
3912 MCHBAR32(0x18dc) = 0x3;
3913 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003914
3915 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003916 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003917 }
3918
Felix Held04be2dd2018-07-29 04:53:22 +02003919 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003920 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003921 MCHBAR32(0x1a10) = 0x4200010e;
3922 MCHBAR32_OR(0x18b8, 0x200);
3923 gav(MCHBAR32(0x1918)); // !!!!
3924 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925
Felix Held04be2dd2018-07-29 04:53:22 +02003926 gav(MCHBAR32(0x18b8)); // !!!!
3927 MCHBAR32(0x18b8) = 0xe00;
3928 gav(MCHBAR32(0x182c)); // !!!!
3929 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003930 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3931 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003932 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3933 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003934
Felix Held04be2dd2018-07-29 04:53:22 +02003935 MCHBAR32_AND(0x18b4, 0xffff7fff);
3936 gav(MCHBAR32(0x1a68)); // !!!!
3937 MCHBAR32(0x1a68) = 0x343800;
3938 gav(MCHBAR32(0x1e68)); // !!!!
3939 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003940
3941 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003942 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943 }
3944
Angel Pons08143572020-07-22 17:47:06 +02003945 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3946 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3947 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3948 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3949 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003950 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3951 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003952 gav(MCHBAR32(0x1af0)); // !!!!
3953 gav(MCHBAR32(0x1af0)); // !!!!
3954 MCHBAR32(0x1af0) = 0x1f020003;
3955 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003956
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003957 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003958 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003959 }
3960
Felix Held04be2dd2018-07-29 04:53:22 +02003961 gav(MCHBAR32(0x1890)); // !!!!
3962 MCHBAR32(0x1890) = 0x80102;
3963 gav(MCHBAR32(0x18b4)); // !!!!
3964 MCHBAR32(0x18b4) = 0x216000;
3965 MCHBAR32(0x18a4) = 0x22222222;
3966 MCHBAR32(0x18a8) = 0x22222222;
3967 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003968
3969 udelay(1000);
3970
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003971 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003972
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003973 if (x2ca8 == 0) {
3974 int j;
3975 if (s3resume && info.cached_training) {
3976 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003977 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003978 info.cached_training->reg2ca9_bit0);
3979 for (i = 0; i < 2; i++)
3980 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003981 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003982 i, j, info.cached_training->reg274265[i][j]);
3983 } else {
3984 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003985 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003986 info.training.reg2ca9_bit0);
3987 for (i = 0; i < 2; i++)
3988 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003989 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003990 i, j, info.training.reg274265[i][j]);
3991 }
3992
3993 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003994
3995 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003996 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003997 }
3998
3999 udelay(1000);
4000
4001 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004002 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004003 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004004 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4005 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4006 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004007
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004008 MCHBAR8(0x1150);
4009 MCHBAR8(0x1151);
4010 MCHBAR8(0x1022);
4011 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004012 MCHBAR32(0x1300) = 0x60606060;
4013 MCHBAR32(0x1304) = 0x60606060;
4014 MCHBAR32(0x1308) = 0x78797a7b;
4015 MCHBAR32(0x130c) = 0x7c7d7e7f;
4016 MCHBAR32(0x1310) = 0x60606060;
4017 MCHBAR32(0x1314) = 0x60606060;
4018 MCHBAR32(0x1318) = 0x60606060;
4019 MCHBAR32(0x131c) = 0x60606060;
4020 MCHBAR32(0x1320) = 0x50515253;
4021 MCHBAR32(0x1324) = 0x54555657;
4022 MCHBAR32(0x1328) = 0x58595a5b;
4023 MCHBAR32(0x132c) = 0x5c5d5e5f;
4024 MCHBAR32(0x1330) = 0x40414243;
4025 MCHBAR32(0x1334) = 0x44454647;
4026 MCHBAR32(0x1338) = 0x48494a4b;
4027 MCHBAR32(0x133c) = 0x4c4d4e4f;
4028 MCHBAR32(0x1340) = 0x30313233;
4029 MCHBAR32(0x1344) = 0x34353637;
4030 MCHBAR32(0x1348) = 0x38393a3b;
4031 MCHBAR32(0x134c) = 0x3c3d3e3f;
4032 MCHBAR32(0x1350) = 0x20212223;
4033 MCHBAR32(0x1354) = 0x24252627;
4034 MCHBAR32(0x1358) = 0x28292a2b;
4035 MCHBAR32(0x135c) = 0x2c2d2e2f;
4036 MCHBAR32(0x1360) = 0x10111213;
4037 MCHBAR32(0x1364) = 0x14151617;
4038 MCHBAR32(0x1368) = 0x18191a1b;
4039 MCHBAR32(0x136c) = 0x1c1d1e1f;
4040 MCHBAR32(0x1370) = 0x10203;
4041 MCHBAR32(0x1374) = 0x4050607;
4042 MCHBAR32(0x1378) = 0x8090a0b;
4043 MCHBAR32(0x137c) = 0xc0d0e0f;
4044 MCHBAR8(0x11cc) = 0x4e;
4045 MCHBAR32(0x1110) = 0x73970404;
4046 MCHBAR32(0x1114) = 0x72960404;
4047 MCHBAR32(0x1118) = 0x6f950404;
4048 MCHBAR32(0x111c) = 0x6d940404;
4049 MCHBAR32(0x1120) = 0x6a930404;
4050 MCHBAR32(0x1124) = 0x68a41404;
4051 MCHBAR32(0x1128) = 0x66a21404;
4052 MCHBAR32(0x112c) = 0x63a01404;
4053 MCHBAR32(0x1130) = 0x609e1404;
4054 MCHBAR32(0x1134) = 0x5f9c1404;
4055 MCHBAR32(0x1138) = 0x5c961404;
4056 MCHBAR32(0x113c) = 0x58a02404;
4057 MCHBAR32(0x1140) = 0x54942404;
4058 MCHBAR32(0x1190) = 0x900080a;
4059 MCHBAR16(0x11c0) = 0xc40b;
4060 MCHBAR16(0x11c2) = 0x303;
4061 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004062 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004063 MCHBAR32(0x11b8) = 0x70c3000;
4064 MCHBAR8(0x11ec) = 0xa;
4065 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004066 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004067 MCHBAR16(0x11ca) = 0xfa;
4068 MCHBAR32(0x11e4) = 0x4e20;
4069 MCHBAR8(0x11bc) = 0xf;
4070 MCHBAR16(0x11da) = 0x19;
4071 MCHBAR16(0x11ba) = 0x470c;
4072 MCHBAR32(0x1680) = 0xe6ffe4ff;
4073 MCHBAR32(0x1684) = 0xdeffdaff;
4074 MCHBAR32(0x1688) = 0xd4ffd0ff;
4075 MCHBAR32(0x168c) = 0xccffc6ff;
4076 MCHBAR32(0x1690) = 0xc0ffbeff;
4077 MCHBAR32(0x1694) = 0xb8ffb0ff;
4078 MCHBAR32(0x1698) = 0xa8ff0000;
4079 MCHBAR32(0x169c) = 0xc00;
4080 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004081 }
4082
Felix Held04be2dd2018-07-29 04:53:22 +02004083 MCHBAR32(0x124c) = 0x15040d00;
4084 MCHBAR32(0x1250) = 0x7f0000;
4085 MCHBAR32(0x1254) = 0x1e220004;
4086 MCHBAR32(0x1258) = 0x4000004;
4087 MCHBAR32(0x1278) = 0x0;
4088 MCHBAR32(0x125c) = 0x0;
4089 MCHBAR32(0x1260) = 0x0;
4090 MCHBAR32(0x1264) = 0x0;
4091 MCHBAR32(0x1268) = 0x0;
4092 MCHBAR32(0x126c) = 0x0;
4093 MCHBAR32(0x1270) = 0x0;
4094 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004095 }
4096
4097 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004098 MCHBAR16(0x1214) = 0x320;
4099 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004100 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4101 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004102 MCHBAR32(0x1400) = 0x13040020;
4103 MCHBAR32(0x1404) = 0xe090120;
4104 MCHBAR32(0x1408) = 0x5120220;
4105 MCHBAR32(0x140c) = 0x5120330;
4106 MCHBAR32(0x1410) = 0xe090220;
4107 MCHBAR32(0x1414) = 0x1010001;
4108 MCHBAR32(0x1418) = 0x1110000;
4109 MCHBAR32(0x141c) = 0x9020020;
4110 MCHBAR32(0x1420) = 0xd090220;
4111 MCHBAR32(0x1424) = 0x2090220;
4112 MCHBAR32(0x1428) = 0x2090330;
4113 MCHBAR32(0x142c) = 0xd090220;
4114 MCHBAR32(0x1430) = 0x1010001;
4115 MCHBAR32(0x1434) = 0x1110000;
4116 MCHBAR32(0x1438) = 0x11040020;
4117 MCHBAR32(0x143c) = 0x4030220;
4118 MCHBAR32(0x1440) = 0x1060220;
4119 MCHBAR32(0x1444) = 0x1060330;
4120 MCHBAR32(0x1448) = 0x4030220;
4121 MCHBAR32(0x144c) = 0x1010001;
4122 MCHBAR32(0x1450) = 0x1110000;
4123 MCHBAR32(0x1454) = 0x4010020;
4124 MCHBAR32(0x1458) = 0xb090220;
4125 MCHBAR32(0x145c) = 0x1090220;
4126 MCHBAR32(0x1460) = 0x1090330;
4127 MCHBAR32(0x1464) = 0xb090220;
4128 MCHBAR32(0x1468) = 0x1010001;
4129 MCHBAR32(0x146c) = 0x1110000;
4130 MCHBAR32(0x1470) = 0xf040020;
4131 MCHBAR32(0x1474) = 0xa090220;
4132 MCHBAR32(0x1478) = 0x1120220;
4133 MCHBAR32(0x147c) = 0x1120330;
4134 MCHBAR32(0x1480) = 0xa090220;
4135 MCHBAR32(0x1484) = 0x1010001;
4136 MCHBAR32(0x1488) = 0x1110000;
4137 MCHBAR32(0x148c) = 0x7020020;
4138 MCHBAR32(0x1490) = 0x1010220;
4139 MCHBAR32(0x1494) = 0x10210;
4140 MCHBAR32(0x1498) = 0x10320;
4141 MCHBAR32(0x149c) = 0x1010220;
4142 MCHBAR32(0x14a0) = 0x1010001;
4143 MCHBAR32(0x14a4) = 0x1110000;
4144 MCHBAR32(0x14a8) = 0xd040020;
4145 MCHBAR32(0x14ac) = 0x8090220;
4146 MCHBAR32(0x14b0) = 0x1111310;
4147 MCHBAR32(0x14b4) = 0x1111420;
4148 MCHBAR32(0x14b8) = 0x8090220;
4149 MCHBAR32(0x14bc) = 0x1010001;
4150 MCHBAR32(0x14c0) = 0x1110000;
4151 MCHBAR32(0x14c4) = 0x3010020;
4152 MCHBAR32(0x14c8) = 0x7090220;
4153 MCHBAR32(0x14cc) = 0x1081310;
4154 MCHBAR32(0x14d0) = 0x1081420;
4155 MCHBAR32(0x14d4) = 0x7090220;
4156 MCHBAR32(0x14d8) = 0x1010001;
4157 MCHBAR32(0x14dc) = 0x1110000;
4158 MCHBAR32(0x14e0) = 0xb040020;
4159 MCHBAR32(0x14e4) = 0x2030220;
4160 MCHBAR32(0x14e8) = 0x1051310;
4161 MCHBAR32(0x14ec) = 0x1051420;
4162 MCHBAR32(0x14f0) = 0x2030220;
4163 MCHBAR32(0x14f4) = 0x1010001;
4164 MCHBAR32(0x14f8) = 0x1110000;
4165 MCHBAR32(0x14fc) = 0x5020020;
4166 MCHBAR32(0x1500) = 0x5090220;
4167 MCHBAR32(0x1504) = 0x2071310;
4168 MCHBAR32(0x1508) = 0x2071420;
4169 MCHBAR32(0x150c) = 0x5090220;
4170 MCHBAR32(0x1510) = 0x1010001;
4171 MCHBAR32(0x1514) = 0x1110000;
4172 MCHBAR32(0x1518) = 0x7040120;
4173 MCHBAR32(0x151c) = 0x2090220;
4174 MCHBAR32(0x1520) = 0x70b1210;
4175 MCHBAR32(0x1524) = 0x70b1310;
4176 MCHBAR32(0x1528) = 0x2090220;
4177 MCHBAR32(0x152c) = 0x1010001;
4178 MCHBAR32(0x1530) = 0x1110000;
4179 MCHBAR32(0x1534) = 0x1010110;
4180 MCHBAR32(0x1538) = 0x1081310;
4181 MCHBAR32(0x153c) = 0x5041200;
4182 MCHBAR32(0x1540) = 0x5041310;
4183 MCHBAR32(0x1544) = 0x1081310;
4184 MCHBAR32(0x1548) = 0x1010001;
4185 MCHBAR32(0x154c) = 0x1110000;
4186 MCHBAR32(0x1550) = 0x1040120;
4187 MCHBAR32(0x1554) = 0x4051210;
4188 MCHBAR32(0x1558) = 0xd051200;
4189 MCHBAR32(0x155c) = 0xd051200;
4190 MCHBAR32(0x1560) = 0x4051210;
4191 MCHBAR32(0x1564) = 0x1010001;
4192 MCHBAR32(0x1568) = 0x1110000;
4193 MCHBAR16(0x1222) = 0x220a;
4194 MCHBAR16(0x123c) = 0x1fc0;
4195 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004196 }
4197
Felix Heldf83d80b2018-07-29 05:30:30 +02004198 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004199 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004200 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004201
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004202 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004203
4204 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004205 MCHBAR8_AND(0x2ca8, ~3);
4206 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004207 /* This issues a CPU reset without resetting the platform */
4208 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004209 /* Write back the S3 state to PM1_CNT to let the reset CPU
4210 know it also needs to take the s3 path. */
4211 if (s3resume)
4212 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4213 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004214 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004215 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004216 }
4217
Felix Held04be2dd2018-07-29 04:53:22 +02004218 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004219 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004220 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004221 MCHBAR16(0x2c20); // !!!!
4222 MCHBAR16(0x2c10); // !!!!
4223 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004224 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004225 udelay(1000);
4226 write_1d0(0, 0x33d, 0, 0);
4227 write_500(&info, 0, 0, 0xb61, 0, 0);
4228 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004229 MCHBAR32(0x1a30) = 0x0;
4230 MCHBAR32(0x1a34) = 0x0;
4231 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4232 (info.populated_ranks[0][0][0] * 0xa0);
4233 MCHBAR16(0x616) = 0x26a;
4234 MCHBAR32(0x134) = 0x856000;
4235 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004236 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4237 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004238 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004239 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4240 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004241 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004242 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004243 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4244 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004245 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4246 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4247 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4248 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4249 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4250 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4251 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4252 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4253 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4254 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004255 }
4256
4257 write_1d0(0x4, 0x151, 4, 1);
4258 write_1d0(0, 0x142, 3, 1);
4259 rdmsr(0x1ac); // !!!!
4260 write_500(&info, 1, 1, 0x6b3, 4, 1);
4261 write_500(&info, 1, 1, 0x6cf, 4, 1);
4262
4263 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4264
4265 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4266 populated_ranks[0]
4267 [0][0]) << 0),
4268 0x1d1, 3, 1);
4269 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4271 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004272 }
4273
4274 set_334(0);
4275
4276 program_base_timings(&info);
4277
Felix Held04be2dd2018-07-29 04:53:22 +02004278 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004279
4280 write_1d0(0x2, 0x1d5, 2, 1);
4281 write_1d0(0x20, 0x166, 7, 1);
4282 write_1d0(0x0, 0xeb, 3, 1);
4283 write_1d0(0x0, 0xf3, 6, 1);
4284
4285 for (channel = 0; channel < NUM_CHANNELS; channel++)
4286 for (lane = 0; lane < 9; lane++) {
4287 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4288 u8 a;
4289 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4290 write_500(&info, channel, a, addr, 6, 1);
4291 }
4292
4293 udelay(1000);
4294
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004295 if (s3resume) {
4296 if (info.cached_training == NULL) {
4297 u32 reg32;
4298 printk(BIOS_ERR,
4299 "Couldn't find training data. Rebooting\n");
4300 reg32 = inl(DEFAULT_PMBASE + 0x04);
4301 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004302 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004303 }
4304 int tm;
4305 info.training = *info.cached_training;
4306 for (tm = 0; tm < 4; tm++)
4307 for (channel = 0; channel < NUM_CHANNELS; channel++)
4308 for (slot = 0; slot < NUM_SLOTS; slot++)
4309 for (rank = 0; rank < NUM_RANKS; rank++)
4310 for (lane = 0; lane < 9; lane++)
4311 write_500(&info,
4312 channel,
4313 info.training.
4314 lane_timings
4315 [tm][channel]
4316 [slot][rank]
4317 [lane],
4318 get_timing_register_addr
4319 (lane, tm,
4320 slot, rank),
4321 9, 0);
4322 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4323 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4324 }
4325
Felix Heldf83d80b2018-07-29 05:30:30 +02004326 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004327 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004328 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004329 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004330
4331 program_board_delay(&info);
4332
Felix Held04be2dd2018-07-29 04:53:22 +02004333 MCHBAR8(0x5ff) = 0x0;
4334 MCHBAR8(0x5ff) = 0x80;
4335 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004336
Felix Held04be2dd2018-07-29 04:53:22 +02004337 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004338 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004339 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004340 gav(read_1d0(0x14b, 7)); // = 0x81023100
4341 write_1d0(0x30, 0x14b, 7, 1);
4342 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4343 write_1d0(7, 0xd6, 6, 1);
4344 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4345 write_1d0(7, 0x328, 6, 1);
4346
4347 for (channel = 0; channel < NUM_CHANNELS; channel++)
4348 set_4cf(&info, channel,
4349 info.populated_ranks[channel][0][0] ? 8 : 0);
4350
4351 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4352 write_1d0(2, 0x116, 4, 1);
4353 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4354 write_1d0(0, 0xae, 6, 1);
4355 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4356 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004357 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4358 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004359 MCHBAR32_AND(0x140, ~0x07000000);
4360 MCHBAR32_AND(0x138, ~0x07000000);
4361 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004362 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004363 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004364 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365
4366 {
4367 u32 t;
4368 u8 val_a1;
4369 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4370 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4371 rmw_1d0(0x320, 0x07,
4372 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4373 rmw_1d0(0x14b, 0x78,
4374 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4375 4), 7,
4376 1);
4377 rmw_1d0(0xce, 0x38,
4378 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4379 4), 6,
4380 1);
4381 }
4382
4383 for (channel = 0; channel < NUM_CHANNELS; channel++)
4384 set_4cf(&info, channel,
4385 info.populated_ranks[channel][0][0] ? 9 : 1);
4386
4387 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004388 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004389 write_1d0(2, 0xae, 6, 1);
4390 write_1d0(2, 0x300, 6, 1);
4391 write_1d0(2, 0x121, 3, 1);
4392 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4393 write_1d0(4, 0xd6, 6, 1);
4394 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4395 write_1d0(4, 0x328, 6, 1);
4396
4397 for (channel = 0; channel < NUM_CHANNELS; channel++)
4398 set_4cf(&info, channel,
4399 info.populated_ranks[channel][0][0] ? 9 : 0);
4400
Felix Held04be2dd2018-07-29 04:53:22 +02004401 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4402 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004403 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004404 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004405 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4406 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4407 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4408 write_1d0(0, 0x21c, 6, 1);
4409 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4410 write_1d0(0x35, 0x14b, 7, 1);
4411
4412 for (channel = 0; channel < NUM_CHANNELS; channel++)
4413 set_4cf(&info, channel,
4414 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4415
4416 set_334(1);
4417
Felix Held04be2dd2018-07-29 04:53:22 +02004418 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004419
4420 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4421 write_500(&info, channel,
4422 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4423 1);
4424 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4425 }
Felix Held04be2dd2018-07-29 04:53:22 +02004426 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4427 MCHBAR16(0x6c0) = 0x14a0;
4428 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4429 MCHBAR16(0x232) = 0x8;
4430 /* 0x40004 or 0 depending on ? */
4431 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4432 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4433 MCHBAR32(0x128) = 0x2150d05;
4434 MCHBAR8(0x12c) = 0x1f;
4435 MCHBAR8(0x12d) = 0x56;
4436 MCHBAR8(0x12e) = 0x31;
4437 MCHBAR8(0x12f) = 0x0;
4438 MCHBAR8(0x271) = 0x2;
4439 MCHBAR8(0x671) = 0x2;
4440 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004441 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004442 MCHBAR32(0x294 + (channel << 10)) =
4443 (info.populated_ranks_mask[channel] & 3) << 16;
4444 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4445 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004446 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004447 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4448 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004449
4450 if (!s3resume)
4451 jedec_init(&info);
4452
4453 int totalrank = 0;
4454 for (channel = 0; channel < NUM_CHANNELS; channel++)
4455 for (slot = 0; slot < NUM_SLOTS; slot++)
4456 for (rank = 0; rank < NUM_RANKS; rank++)
4457 if (info.populated_ranks[channel][slot][rank]) {
4458 jedec_read(&info, channel, slot, rank,
4459 totalrank, 0xa, 0x400);
4460 totalrank++;
4461 }
4462
Felix Held04be2dd2018-07-29 04:53:22 +02004463 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004464
Felix Heldf83d80b2018-07-29 05:30:30 +02004465 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4466 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004467
4468 if (!s3resume) {
4469 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004470 MCHBAR32(0x294 + (channel << 10)) =
4471 (info.populated_ranks_mask[channel] & 3) << 16;
4472 MCHBAR16(0x298 + (channel << 10)) =
4473 info.populated_ranks[channel][0][0] |
4474 (info.populated_ranks[channel][0][1] << 5);
4475 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004477 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004478
4479 {
4480 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004481 a = MCHBAR8(0x243);
4482 b = MCHBAR8(0x643);
4483 MCHBAR8(0x243) = a | 2;
4484 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004485 }
4486
4487 write_1d0(7, 0x19b, 3, 1);
4488 write_1d0(7, 0x1c0, 3, 1);
4489 write_1d0(4, 0x1c6, 4, 1);
4490 write_1d0(4, 0x1cc, 4, 1);
4491 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4492 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004493 MCHBAR32(0x584) = 0xfffff;
4494 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495
4496 for (channel = 0; channel < NUM_CHANNELS; channel++)
4497 for (slot = 0; slot < NUM_SLOTS; slot++)
4498 for (rank = 0; rank < NUM_RANKS; rank++)
4499 if (info.
4500 populated_ranks[channel][slot]
4501 [rank])
4502 config_rank(&info, s3resume,
4503 channel, slot,
4504 rank);
4505
Felix Held04be2dd2018-07-29 04:53:22 +02004506 MCHBAR8(0x243) = 0x1;
4507 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508 }
4509
4510 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004511 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512 write_26c(0, 0x820);
4513 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004514 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004515 /* end */
4516
4517 if (s3resume) {
4518 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004519 MCHBAR32(0x294 + (channel << 10)) =
4520 (info.populated_ranks_mask[channel] & 3) << 16;
4521 MCHBAR16(0x298 + (channel << 10)) =
4522 info.populated_ranks[channel][0][0] |
4523 (info.populated_ranks[channel][0][1] << 5);
4524 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004525 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004526 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004527 }
4528
Felix Held04be2dd2018-07-29 04:53:22 +02004529 MCHBAR32_AND(0xfa4, ~0x01000002);
4530 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004532 /* Before training. */
4533 timestamp_add_now(103);
4534
4535 if (!s3resume)
4536 ram_training(&info);
4537
4538 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004539 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540
4541 dump_timings(&info);
4542
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 program_modules_memory_map(&info, 0);
4544 program_total_memory_map(&info);
4545
4546 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004548 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004549 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004551 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004552 else
Felix Held04be2dd2018-07-29 04:53:22 +02004553 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554
Felix Held04be2dd2018-07-29 04:53:22 +02004555 MCHBAR32_AND(0xfac, ~0x80000000);
4556 MCHBAR32(0xfb4) = 0x4800;
4557 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4558 MCHBAR32(0xe94) = 0x7ffff;
4559 MCHBAR32(0xfc0) = 0x80002040;
4560 MCHBAR32(0xfc4) = 0x701246;
4561 MCHBAR8_AND(0xfc8, ~0x70);
4562 MCHBAR32_OR(0xe5c, 0x1000000);
4563 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4564 MCHBAR32(0x50) = 0x700b0;
4565 MCHBAR32(0x3c) = 0x10;
4566 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4567 MCHBAR8_OR(0xff4, 0x2);
4568 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569
Felix Held04be2dd2018-07-29 04:53:22 +02004570 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4571 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4572 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004574 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4575 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4576 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 {
4579 u32 eax;
4580
4581 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4583 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4584 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585 }
4586
4587 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004591 else
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593
Felix Held04be2dd2018-07-29 04:53:22 +02004594 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004595
Felix Held04be2dd2018-07-29 04:53:22 +02004596 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599 else
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004601 }
4602
Felix Held04be2dd2018-07-29 04:53:22 +02004603 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604
4605 {
4606 u8 al;
4607 al = 0xd;
4608 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4609 al += 2;
4610 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004611 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004612 }
4613
4614 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004615 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4616 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4617 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4618 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004619 }
4620 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004621 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004622 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004623 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004624 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004625 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004626 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004627 MCHBAR8_OR(0x1210, 2);
4628 MCHBAR32(0x1200) = 0x8800440;
4629 MCHBAR32(0x1204) = 0x53ff0453;
4630 MCHBAR32(0x1208) = 0x19002043;
4631 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632
4633 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR16(0x1214) = 0x220;
4635 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636 }
4637
Felix Held04be2dd2018-07-29 04:53:22 +02004638 MCHBAR8_OR(0x1214, 0x4);
4639 MCHBAR8(0x120c) = 0x1;
4640 MCHBAR8(0x1218) = 0x3;
4641 MCHBAR8(0x121a) = 0x3;
4642 MCHBAR8(0x121c) = 0x3;
4643 MCHBAR16(0xc14) = 0x0;
4644 MCHBAR16(0xc20) = 0x0;
4645 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
4647 /* revision dependent here. */
4648
Felix Held04be2dd2018-07-29 04:53:22 +02004649 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004650
4651 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653
Felix Held04be2dd2018-07-29 04:53:22 +02004654 MCHBAR16_OR(0x1230, 0x8000);
4655 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004656
4657 u8 bl, ebpb;
4658 u16 reg_1020;
4659
Felix Held04be2dd2018-07-29 04:53:22 +02004660 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4661 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004662
Felix Held04be2dd2018-07-29 04:53:22 +02004663 MCHBAR32(0x1000) = 0x100;
4664 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004665
4666 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004667 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004668 bl = reg_1020 >> 8;
4669 ebpb = reg_1020 & 0xff;
4670 } else {
4671 ebpb = 0;
4672 bl = 8;
4673 }
4674
4675 rdmsr(0x1a2);
4676
Felix Held04be2dd2018-07-29 04:53:22 +02004677 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678
Felix Held04be2dd2018-07-29 04:53:22 +02004679 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682
Felix Held04be2dd2018-07-29 04:53:22 +02004683 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004685 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4686 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004687 }
4688
4689 setup_heci_uma(&info);
4690
4691 if (info.uma_enabled) {
4692 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR32_OR(0x11b0, 0x4000);
4694 MCHBAR32_OR(0x11b4, 0x4000);
4695 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004696
Felix Held04be2dd2018-07-29 04:53:22 +02004697 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4698 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4699 MCHBAR16_OR(0x1170, 0x1000);
4700
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004702
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004704 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004705 ;
4706 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707 }
4708
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004709 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4710 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004712 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004714 udelay(1000);
4715 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004716 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4717
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004718 if (!s3resume)
4719 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004720 if (s3resume && cbmem_wasnot_inited) {
4721 u32 reg32;
4722 printk(BIOS_ERR, "Failed S3 resume.\n");
4723 ram_check(0x100000, 0x200000);
4724
4725 /* Clear SLP_TYPE. */
4726 reg32 = inl(DEFAULT_PMBASE + 0x04);
4727 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4728
4729 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004730 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004731 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004732}