blob: ecfbd8a3d11ba0f6b4bb142af345a39a91c4e3bc [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
Arthur Heymansdc71e252018-01-29 10:14:48 +010064#define MRC_CACHE_VERSION 1
65
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
195 u32 heci_bar;
196 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600197 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100198
199 struct ram_training training;
200 u32 last_500_command[2];
201
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100202 u32 delay46_ps[2];
203 u32 delay54_ps[2];
204 u8 revision_flag_1;
205 u8 some_delay_1_cycle_floor;
206 u8 some_delay_2_halfcycles_ceil;
207 u8 some_delay_3_ps_rounded;
208
209 const struct ram_training *cached_training;
210};
211
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200212/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100213timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200214
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100215static void
216write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
217 int flag);
218
219/* OK */
220static u16
221read_500(struct raminfo *info, int channel, u16 addr, int split)
222{
223 u32 val;
224 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200225 MCHBAR32(0x500 + (channel << 10)) = 0;
226 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
227 ;
228 MCHBAR32(0x500 + (channel << 10)) =
229 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
230 + 0xb88 - addr);
231 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
232 ;
233 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100234 return val & ((1 << split) - 1);
235}
236
237/* OK */
238static void
239write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
240 int flag)
241{
242 if (info->last_500_command[channel] == 0x80000000) {
243 info->last_500_command[channel] = 0x40000000;
244 write_500(info, channel, 0, 0xb61, 0, 0);
245 }
Felix Held04be2dd2018-07-29 04:53:22 +0200246 MCHBAR32(0x500 + (channel << 10)) = 0;
247 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
248 ;
249 MCHBAR32(0x504 + (channel << 10)) =
250 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
251 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200252 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200253 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100254}
255
256static int rw_test(int rank)
257{
258 const u32 mask = 0xf00fc33c;
259 int ok = 0xff;
260 int i;
261 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800262 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100263 sfence();
264 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800265 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100266 sfence();
267 for (i = 0; i < 32; i++) {
268 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800269 write32p((rank << 28) | (i << 3), pat);
270 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100271 }
272 sfence();
273 for (i = 0; i < 32; i++) {
274 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
275 int j;
276 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800277 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 for (j = 0; j < 4; j++)
279 if (((val >> (j * 8)) & 0xff) != pat)
280 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800281 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 for (j = 0; j < 4; j++)
283 if (((val >> (j * 8)) & 0xff) != pat)
284 ok &= ~(16 << j);
285 }
286 sfence();
287 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 sfence();
290 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800291 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100292
293 return ok;
294}
295
296static void
297program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
298{
299 int lane;
300 for (lane = 0; lane < 8; lane++) {
301 write_500(info, channel,
302 base +
303 info->training.
304 lane_timings[2][channel][slot][rank][lane],
305 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
306 write_500(info, channel,
307 base +
308 info->training.
309 lane_timings[3][channel][slot][rank][lane],
310 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
311 }
312}
313
314static void write_26c(int channel, u16 si)
315{
Felix Held04be2dd2018-07-29 04:53:22 +0200316 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
317 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
318 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100319}
320
321static u32 get_580(int channel, u8 addr)
322{
323 u32 ret;
324 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200325 MCHBAR8(0x5ff) = 0x0;
326 MCHBAR8(0x5ff) = 0x80;
327 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
328 MCHBAR8_OR(0x580 + (channel << 10), 1);
329 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
330 ;
331 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332 return ret;
333}
334
335const int cached_config = 0;
336
337#define NUM_CHANNELS 2
338#define NUM_SLOTS 2
339#define NUM_RANKS 2
340#define RANK_SHIFT 28
341#define CHANNEL_SHIFT 10
342
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100343static void seq9(struct raminfo *info, int channel, int slot, int rank)
344{
345 int i, lane;
346
347 for (i = 0; i < 2; i++)
348 for (lane = 0; lane < 8; lane++)
349 write_500(info, channel,
350 info->training.lane_timings[i +
351 1][channel][slot]
352 [rank][lane], get_timing_register_addr(lane,
353 i + 1,
354 slot,
355 rank),
356 9, 0);
357
358 write_1d0(1, 0x103, 6, 1);
359 for (lane = 0; lane < 8; lane++)
360 write_500(info, channel,
361 info->training.
362 lane_timings[0][channel][slot][rank][lane],
363 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
364
365 for (i = 0; i < 2; i++) {
366 for (lane = 0; lane < 8; lane++)
367 write_500(info, channel,
368 info->training.lane_timings[i +
369 1][channel][slot]
370 [rank][lane], get_timing_register_addr(lane,
371 i + 1,
372 slot,
373 rank),
374 9, 0);
375 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
376 }
377
378 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200379 MCHBAR8(0x5ff) = 0x0;
380 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100381 write_1d0(0x2, 0x142, 3, 1);
382 for (lane = 0; lane < 8; lane++) {
383 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
384 info->training.lane_timings[2][channel][slot][rank][lane] =
385 read_500(info, channel,
386 get_timing_register_addr(lane, 2, slot, rank), 9);
387 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
388 info->training.lane_timings[3][channel][slot][rank][lane] =
389 info->training.lane_timings[2][channel][slot][rank][lane] +
390 0x20;
391 }
392}
393
394static int count_ranks_in_channel(struct raminfo *info, int channel)
395{
396 int slot, rank;
397 int res = 0;
398 for (slot = 0; slot < NUM_SLOTS; slot++)
399 for (rank = 0; rank < NUM_SLOTS; rank++)
400 res += info->populated_ranks[channel][slot][rank];
401 return res;
402}
403
404static void
405config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
406{
407 int add;
408
409 write_1d0(0, 0x178, 7, 1);
410 seq9(info, channel, slot, rank);
411 program_timings(info, 0x80, channel, slot, rank);
412
413 if (channel == 0)
414 add = count_ranks_in_channel(info, 1);
415 else
416 add = 0;
417 if (!s3resume)
418 gav(rw_test(rank + add));
419 program_timings(info, 0x00, channel, slot, rank);
420 if (!s3resume)
421 gav(rw_test(rank + add));
422 if (!s3resume)
423 gav(rw_test(rank + add));
424 write_1d0(0, 0x142, 3, 1);
425 write_1d0(0, 0x103, 6, 1);
426
427 gav(get_580(channel, 0xc | (rank << 5)));
428 gav(read_1d0(0x142, 3));
429
Felix Held04be2dd2018-07-29 04:53:22 +0200430 MCHBAR8(0x5ff) = 0x0;
431 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100432}
433
434static void set_4cf(struct raminfo *info, int channel, u8 val)
435{
436 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
437 write_500(info, channel, val, 0x4cf, 4, 1);
438 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
439 write_500(info, channel, val, 0x659, 4, 1);
440 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
441 write_500(info, channel, val, 0x697, 4, 1);
442}
443
444static void set_334(int zero)
445{
446 int j, k, channel;
447 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
448 u32 vd8[2][16];
449
450 for (channel = 0; channel < NUM_CHANNELS; channel++) {
451 for (j = 0; j < 4; j++) {
452 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
453 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
454 u16 c;
455 if ((j == 0 || j == 3) && zero)
456 c = 0;
457 else if (j == 3)
458 c = 0x5f;
459 else
460 c = 0x5f5f;
461
462 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200463 MCHBAR32(0x138 + 8 * k) =
464 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100465 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200466 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100467 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200468 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100469 }
470
Felix Held22ca8cb2018-07-29 05:09:44 +0200471 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
472 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200473 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
474 zero ? 0 : (0x18191819 & lmask);
475 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
476 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : (a & lmask);
478 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
479 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100480 }
481 }
482
Felix Held04be2dd2018-07-29 04:53:22 +0200483 MCHBAR32_OR(0x130, 1);
484 while (MCHBAR8(0x130) & 1)
485 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486}
487
488static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
489{
490 u32 v;
491 v = read_1d0(addr, split);
492 write_1d0((v & and) | or, addr, split, flag);
493}
494
495static int find_highest_bit_set(u16 val)
496{
497 int i;
498 for (i = 15; i >= 0; i--)
499 if (val & (1 << i))
500 return i;
501 return -1;
502}
503
504static int find_lowest_bit_set32(u32 val)
505{
506 int i;
507 for (i = 0; i < 32; i++)
508 if (val & (1 << i))
509 return i;
510 return -1;
511}
512
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100513enum {
514 DEVICE_TYPE = 2,
515 MODULE_TYPE = 3,
516 DENSITY = 4,
517 RANKS_AND_DQ = 7,
518 MEMORY_BUS_WIDTH = 8,
519 TIMEBASE_DIVIDEND = 10,
520 TIMEBASE_DIVISOR = 11,
521 CYCLETIME = 12,
522
523 CAS_LATENCIES_LSB = 14,
524 CAS_LATENCIES_MSB = 15,
525 CAS_LATENCY_TIME = 16,
526 THERMAL_AND_REFRESH = 31,
527 REFERENCE_RAW_CARD_USED = 62,
528 RANK1_ADDRESS_MAPPING = 63
529};
530
531static void calculate_timings(struct raminfo *info)
532{
Martin Roth468d02c2019-10-23 21:44:42 -0600533 unsigned int cycletime;
534 unsigned int cas_latency_time;
535 unsigned int supported_cas_latencies;
536 unsigned int channel, slot;
537 unsigned int clock_speed_index;
538 unsigned int min_cas_latency;
539 unsigned int cas_latency;
540 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100541
542 /* Find common CAS latency */
543 supported_cas_latencies = 0x3fe;
544 for (channel = 0; channel < NUM_CHANNELS; channel++)
545 for (slot = 0; slot < NUM_SLOTS; slot++)
546 if (info->populated_ranks[channel][slot][0])
547 supported_cas_latencies &=
548 2 *
549 (info->
550 spd[channel][slot][CAS_LATENCIES_LSB] |
551 (info->
552 spd[channel][slot][CAS_LATENCIES_MSB] <<
553 8));
554
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100555 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100556
557 cycletime = min_cycletime[max_clock_index];
558 cas_latency_time = min_cas_latency_time[max_clock_index];
559
560 for (channel = 0; channel < NUM_CHANNELS; channel++)
561 for (slot = 0; slot < NUM_SLOTS; slot++)
562 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600563 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100564 timebase =
565 1000 *
566 info->
567 spd[channel][slot][TIMEBASE_DIVIDEND] /
568 info->spd[channel][slot][TIMEBASE_DIVISOR];
569 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100570 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100571 timebase *
572 info->spd[channel][slot][CYCLETIME]);
573 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100574 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100575 timebase *
576 info->
577 spd[channel][slot][CAS_LATENCY_TIME]);
578 }
Jacob Garber3c193822019-06-10 18:23:32 -0600579 if (cycletime > min_cycletime[0])
580 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100581 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
582 if (cycletime == min_cycletime[clock_speed_index])
583 break;
584 if (cycletime > min_cycletime[clock_speed_index]) {
585 clock_speed_index--;
586 cycletime = min_cycletime[clock_speed_index];
587 break;
588 }
589 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100590 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100591 cas_latency = 0;
592 while (supported_cas_latencies) {
593 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
594 if (cas_latency <= min_cas_latency)
595 break;
596 supported_cas_latencies &=
597 ~(1 << find_highest_bit_set(supported_cas_latencies));
598 }
599
600 if (cas_latency != min_cas_latency && clock_speed_index)
601 clock_speed_index--;
602
603 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
604 die("Couldn't configure DRAM");
605 info->clock_speed_index = clock_speed_index;
606 info->cas_latency = cas_latency;
607}
608
609static void program_base_timings(struct raminfo *info)
610{
Martin Roth468d02c2019-10-23 21:44:42 -0600611 unsigned int channel;
612 unsigned int slot, rank, lane;
613 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100614 int i;
615
616 extended_silicon_revision = info->silicon_revision;
617 if (info->silicon_revision == 0)
618 for (channel = 0; channel < NUM_CHANNELS; channel++)
619 for (slot = 0; slot < NUM_SLOTS; slot++)
620 if ((info->
621 spd[channel][slot][MODULE_TYPE] & 0xF) ==
622 3)
623 extended_silicon_revision = 4;
624
625 for (channel = 0; channel < NUM_CHANNELS; channel++) {
626 for (slot = 0; slot < NUM_SLOTS; slot++)
627 for (rank = 0; rank < NUM_SLOTS; rank++) {
628 int card_timing_2;
629 if (!info->populated_ranks[channel][slot][rank])
630 continue;
631
632 for (lane = 0; lane < 9; lane++) {
633 int tm_reg;
634 int card_timing;
635
636 card_timing = 0;
637 if ((info->
638 spd[channel][slot][MODULE_TYPE] &
639 0xF) == 3) {
640 int reference_card;
641 reference_card =
642 info->
643 spd[channel][slot]
644 [REFERENCE_RAW_CARD_USED] &
645 0x1f;
646 if (reference_card == 3)
647 card_timing =
648 u16_ffd1188[0][lane]
649 [info->
650 clock_speed_index];
651 if (reference_card == 5)
652 card_timing =
653 u16_ffd1188[1][lane]
654 [info->
655 clock_speed_index];
656 }
657
658 info->training.
659 lane_timings[0][channel][slot][rank]
660 [lane] =
661 u8_FFFD1218[info->
662 clock_speed_index];
663 info->training.
664 lane_timings[1][channel][slot][rank]
665 [lane] = 256;
666
667 for (tm_reg = 2; tm_reg < 4; tm_reg++)
668 info->training.
669 lane_timings[tm_reg]
670 [channel][slot][rank][lane]
671 =
672 u8_FFFD1240[channel]
673 [extended_silicon_revision]
674 [lane][2 * slot +
675 rank][info->
676 clock_speed_index]
677 + info->max4048[channel]
678 +
679 u8_FFFD0C78[channel]
680 [extended_silicon_revision]
681 [info->
682 mode4030[channel]][slot]
683 [rank][info->
684 clock_speed_index]
685 + card_timing;
686 for (tm_reg = 0; tm_reg < 4; tm_reg++)
687 write_500(info, channel,
688 info->training.
689 lane_timings[tm_reg]
690 [channel][slot][rank]
691 [lane],
692 get_timing_register_addr
693 (lane, tm_reg, slot,
694 rank), 9, 0);
695 }
696
697 card_timing_2 = 0;
698 if (!(extended_silicon_revision != 4
699 || (info->
700 populated_ranks_mask[channel] & 5) ==
701 5)) {
702 if ((info->
703 spd[channel][slot]
704 [REFERENCE_RAW_CARD_USED] & 0x1F)
705 == 3)
706 card_timing_2 =
707 u16_FFFE0EB8[0][info->
708 clock_speed_index];
709 if ((info->
710 spd[channel][slot]
711 [REFERENCE_RAW_CARD_USED] & 0x1F)
712 == 5)
713 card_timing_2 =
714 u16_FFFE0EB8[1][info->
715 clock_speed_index];
716 }
717
718 for (i = 0; i < 3; i++)
719 write_500(info, channel,
720 (card_timing_2 +
721 info->max4048[channel]
722 +
723 u8_FFFD0EF8[channel]
724 [extended_silicon_revision]
725 [info->
726 mode4030[channel]][info->
727 clock_speed_index]),
728 u16_fffd0c50[i][slot][rank],
729 8, 1);
730 write_500(info, channel,
731 (info->max4048[channel] +
732 u8_FFFD0C78[channel]
733 [extended_silicon_revision][info->
734 mode4030
735 [channel]]
736 [slot][rank][info->
737 clock_speed_index]),
738 u16_fffd0c70[slot][rank], 7, 1);
739 }
740 if (!info->populated_ranks_mask[channel])
741 continue;
742 for (i = 0; i < 3; i++)
743 write_500(info, channel,
744 (info->max4048[channel] +
745 info->avg4044[channel]
746 +
747 u8_FFFD17E0[channel]
748 [extended_silicon_revision][info->
749 mode4030
750 [channel]][info->
751 clock_speed_index]),
752 u16_fffd0c68[i], 8, 1);
753 }
754}
755
756static unsigned int fsbcycle_ps(struct raminfo *info)
757{
758 return 900000 / info->fsb_frequency;
759}
760
761/* The time of DDR transfer in ps. */
762static unsigned int halfcycle_ps(struct raminfo *info)
763{
764 return 3750 / (info->clock_speed_index + 3);
765}
766
767/* The time of clock cycle in ps. */
768static unsigned int cycle_ps(struct raminfo *info)
769{
770 return 2 * halfcycle_ps(info);
771}
772
773/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600774static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100775{
776 return (info->clock_speed_index + 3) * 120;
777}
778
779/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600780static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100781{
782 return 100 * frequency_11(info) / 9;
783}
784
Martin Roth468d02c2019-10-23 21:44:42 -0600785static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786{
787 return (frequency_11(info) * 2) * ps / 900000;
788}
789
Martin Roth468d02c2019-10-23 21:44:42 -0600790static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100791{
792 return (frequency_11(info)) * ns / 900;
793}
794
795static void compute_derived_timings(struct raminfo *info)
796{
Martin Roth468d02c2019-10-23 21:44:42 -0600797 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100798 int extended_silicon_revision;
799 int some_delay_1_ps;
800 int some_delay_2_ps;
801 int some_delay_2_halfcycles_ceil;
802 int some_delay_2_halfcycles_floor;
803 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100804 int some_delay_3_ps_rounded;
805 int some_delay_1_cycle_ceil;
806 int some_delay_1_cycle_floor;
807
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100808 some_delay_3_ps_rounded = 0;
809 extended_silicon_revision = info->silicon_revision;
810 if (!info->silicon_revision)
811 for (channel = 0; channel < NUM_CHANNELS; channel++)
812 for (slot = 0; slot < NUM_SLOTS; slot++)
813 if ((info->
814 spd[channel][slot][MODULE_TYPE] & 0xF) ==
815 3)
816 extended_silicon_revision = 4;
817 if (info->board_lane_delay[7] < 5)
818 info->board_lane_delay[7] = 5;
819 info->revision_flag_1 = 2;
820 if (info->silicon_revision == 2 || info->silicon_revision == 3)
821 info->revision_flag_1 = 0;
822 if (info->revision < 16)
823 info->revision_flag_1 = 0;
824
825 if (info->revision < 8)
826 info->revision_flag_1 = 0;
827 if (info->revision >= 8 && (info->silicon_revision == 0
828 || info->silicon_revision == 1))
829 some_delay_2_ps = 735;
830 else
831 some_delay_2_ps = 750;
832
833 if (info->revision >= 0x10 && (info->silicon_revision == 0
834 || info->silicon_revision == 1))
835 some_delay_1_ps = 3929;
836 else
837 some_delay_1_ps = 3490;
838
839 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
840 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
841 if (some_delay_1_ps % cycle_ps(info))
842 some_delay_1_cycle_ceil++;
843 else
844 some_delay_1_cycle_floor--;
845 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
846 if (info->revision_flag_1)
847 some_delay_2_ps = halfcycle_ps(info) >> 6;
848 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100849 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100850 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
851 375;
852 some_delay_3_ps =
853 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
854 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200855 if (some_delay_3_ps >= 150) {
856 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100857 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200858 some_delay_3_ps_rounded =
859 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
860 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100861 }
862 some_delay_2_halfcycles_ceil =
863 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
864 2 * (some_delay_1_cycle_ceil - 1);
865 if (info->revision_flag_1 && some_delay_3_ps < 150)
866 some_delay_2_halfcycles_ceil++;
867 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
868 if (info->revision < 0x10)
869 some_delay_2_halfcycles_floor =
870 some_delay_2_halfcycles_ceil - 1;
871 if (!info->revision_flag_1)
872 some_delay_2_halfcycles_floor++;
873 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
874 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
875 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
876 || (info->populated_ranks[1][0][0]
877 && info->populated_ranks[1][1][0]))
878 info->max_slots_used_in_channel = 2;
879 else
880 info->max_slots_used_in_channel = 1;
881 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200882 MCHBAR32(0x244 + (channel << 10)) =
883 ((info->revision < 8) ? 1 : 0x200) |
884 ((2 - info->max_slots_used_in_channel) << 17) |
885 (channel << 21) |
886 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100887 if (info->max_slots_used_in_channel == 1) {
888 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
889 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
890 } else {
891 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 */
892 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
893 || (count_ranks_in_channel(info, 1) ==
894 2)) ? 2 : 3;
895 }
896 for (channel = 0; channel < NUM_CHANNELS; channel++) {
897 int max_of_unk;
898 int min_of_unk_2;
899
900 int i, count;
901 int sum;
902
903 if (!info->populated_ranks_mask[channel])
904 continue;
905
906 max_of_unk = 0;
907 min_of_unk_2 = 32767;
908
909 sum = 0;
910 count = 0;
911 for (i = 0; i < 3; i++) {
912 int unk1;
913 if (info->revision < 8)
914 unk1 =
915 u8_FFFD1891[0][channel][info->
916 clock_speed_index]
917 [i];
918 else if (!
919 (info->revision >= 0x10
920 || info->revision_flag_1))
921 unk1 =
922 u8_FFFD1891[1][channel][info->
923 clock_speed_index]
924 [i];
925 else
926 unk1 = 0;
927 for (slot = 0; slot < NUM_SLOTS; slot++)
928 for (rank = 0; rank < NUM_RANKS; rank++) {
929 int a = 0;
930 int b = 0;
931
932 if (!info->
933 populated_ranks[channel][slot]
934 [rank])
935 continue;
936 if (extended_silicon_revision == 4
937 && (info->
938 populated_ranks_mask[channel] &
939 5) != 5) {
940 if ((info->
941 spd[channel][slot]
942 [REFERENCE_RAW_CARD_USED] &
943 0x1F) == 3) {
944 a = u16_ffd1178[0]
945 [info->
946 clock_speed_index];
947 b = u16_fe0eb8[0][info->
948 clock_speed_index];
949 } else
950 if ((info->
951 spd[channel][slot]
952 [REFERENCE_RAW_CARD_USED]
953 & 0x1F) == 5) {
954 a = u16_ffd1178[1]
955 [info->
956 clock_speed_index];
957 b = u16_fe0eb8[1][info->
958 clock_speed_index];
959 }
960 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100961 min_of_unk_2 = MIN(min_of_unk_2, a);
962 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100963 if (rank == 0) {
964 sum += a;
965 count++;
966 }
967 {
968 int t;
969 t = b +
970 u8_FFFD0EF8[channel]
971 [extended_silicon_revision]
972 [info->
973 mode4030[channel]][info->
974 clock_speed_index];
975 if (unk1 >= t)
976 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100977 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100978 unk1 - t);
979 }
980 }
981 {
982 int t =
983 u8_FFFD17E0[channel]
984 [extended_silicon_revision][info->
985 mode4030
986 [channel]]
987 [info->clock_speed_index] + min_of_unk_2;
988 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100989 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100990 }
991 }
992
Jacob Garber64fb4a32019-06-10 17:29:18 -0600993 if (count == 0)
994 die("No memory ranks found for channel %u\n", channel);
995
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100996 info->avg4044[channel] = sum / count;
997 info->max4048[channel] = max_of_unk;
998 }
999}
1000
1001static void jedec_read(struct raminfo *info,
1002 int channel, int slot, int rank,
1003 int total_rank, u8 addr3, unsigned int value)
1004{
1005 /* Handle mirrored mapping. */
1006 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001007 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1008 ((addr3 >> 1) & 0x10);
1009 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1010 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001011
1012 /* Handle mirrored mapping. */
1013 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1014 value =
1015 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1016 << 1);
1017
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001018 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001019
Felix Held04be2dd2018-07-29 04:53:22 +02001020 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1021 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001023 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001024}
1025
1026enum {
1027 MR1_RZQ12 = 512,
1028 MR1_RZQ2 = 64,
1029 MR1_RZQ4 = 4,
1030 MR1_ODS34OHM = 2
1031};
1032
1033enum {
1034 MR0_BT_INTERLEAVED = 8,
1035 MR0_DLL_RESET_ON = 256
1036};
1037
1038enum {
1039 MR2_RTT_WR_DISABLED = 0,
1040 MR2_RZQ2 = 1 << 10
1041};
1042
1043static void jedec_init(struct raminfo *info)
1044{
1045 int write_recovery;
1046 int channel, slot, rank;
1047 int total_rank;
1048 int dll_on;
1049 int self_refresh_temperature;
1050 int auto_self_refresh;
1051
1052 auto_self_refresh = 1;
1053 self_refresh_temperature = 1;
1054 if (info->board_lane_delay[3] <= 10) {
1055 if (info->board_lane_delay[3] <= 8)
1056 write_recovery = info->board_lane_delay[3] - 4;
1057 else
1058 write_recovery = 5;
1059 } else {
1060 write_recovery = 6;
1061 }
1062 FOR_POPULATED_RANKS {
1063 auto_self_refresh &=
1064 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1065 self_refresh_temperature &=
1066 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1067 }
1068 if (auto_self_refresh == 1)
1069 self_refresh_temperature = 0;
1070
1071 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1072 || (info->populated_ranks[0][0][0]
1073 && info->populated_ranks[0][1][0])
1074 || (info->populated_ranks[1][0][0]
1075 && info->populated_ranks[1][1][0]));
1076
1077 total_rank = 0;
1078
1079 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1080 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1081 int rzq_reg58e;
1082
1083 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1084 rzq_reg58e = 64;
1085 rtt = MR1_RZQ2;
1086 if (info->clock_speed_index != 0) {
1087 rzq_reg58e = 4;
1088 if (info->populated_ranks_mask[channel] == 3)
1089 rtt = MR1_RZQ4;
1090 }
1091 } else {
1092 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1093 rtt = MR1_RZQ12;
1094 rzq_reg58e = 64;
1095 rtt_wr = MR2_RZQ2;
1096 } else {
1097 rzq_reg58e = 4;
1098 rtt = MR1_RZQ4;
1099 }
1100 }
1101
Felix Held04be2dd2018-07-29 04:53:22 +02001102 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1103 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1104 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1105 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1106 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001107
1108 for (slot = 0; slot < NUM_SLOTS; slot++)
1109 for (rank = 0; rank < NUM_RANKS; rank++)
1110 if (info->populated_ranks[channel][slot][rank]) {
1111 jedec_read(info, channel, slot, rank,
1112 total_rank, 0x28,
1113 rtt_wr | (info->
1114 clock_speed_index
1115 << 3)
1116 | (auto_self_refresh << 6) |
1117 (self_refresh_temperature <<
1118 7));
1119 jedec_read(info, channel, slot, rank,
1120 total_rank, 0x38, 0);
1121 jedec_read(info, channel, slot, rank,
1122 total_rank, 0x18,
1123 rtt | MR1_ODS34OHM);
1124 jedec_read(info, channel, slot, rank,
1125 total_rank, 6,
1126 (dll_on << 12) |
1127 (write_recovery << 9)
1128 | ((info->cas_latency - 4) <<
1129 4) | MR0_BT_INTERLEAVED |
1130 MR0_DLL_RESET_ON);
1131 total_rank++;
1132 }
1133 }
1134}
1135
1136static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1137{
Martin Roth468d02c2019-10-23 21:44:42 -06001138 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001139 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1140 unsigned int channel_0_non_interleaved;
1141
1142 FOR_ALL_RANKS {
1143 if (info->populated_ranks[channel][slot][rank]) {
1144 total_mb[channel] +=
1145 pre_jedec ? 256 : (256 << info->
1146 density[channel][slot] >> info->
1147 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001148 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1149 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1150 (info->is_x16_module[channel][slot] |
1151 ((info->density[channel][slot] + 1) << 1))) |
1152 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001153 }
Felix Held04be2dd2018-07-29 04:53:22 +02001154 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1155 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001156 }
1157
1158 info->total_memory_mb = total_mb[0] + total_mb[1];
1159
1160 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001161 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001162 info->non_interleaved_part_mb =
1163 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1164 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001165 MCHBAR32(0x100) = channel_0_non_interleaved |
1166 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001168 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001169}
1170
1171static void program_board_delay(struct raminfo *info)
1172{
1173 int cas_latency_shift;
1174 int some_delay_ns;
1175 int some_delay_3_half_cycles;
1176
Martin Roth468d02c2019-10-23 21:44:42 -06001177 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001178 int high_multiplier;
1179 int lane_3_delay;
1180 int cas_latency_derived;
1181
1182 high_multiplier = 0;
1183 some_delay_ns = 200;
1184 some_delay_3_half_cycles = 4;
1185 cas_latency_shift = info->silicon_revision == 0
1186 || info->silicon_revision == 1 ? 1 : 0;
1187 if (info->revision < 8) {
1188 some_delay_ns = 600;
1189 cas_latency_shift = 0;
1190 }
1191 {
1192 int speed_bit;
1193 speed_bit =
1194 ((info->clock_speed_index > 1
1195 || (info->silicon_revision != 2
1196 && info->silicon_revision != 3))) ^ (info->revision >=
1197 0x10);
1198 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1199 3, 1);
1200 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1201 3, 1);
1202 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1203 && (info->silicon_revision == 2
1204 || info->silicon_revision == 3))
1205 rmw_1d0(0x116, 5, 2, 4, 1);
1206 }
Felix Held04be2dd2018-07-29 04:53:22 +02001207 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1208 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001209
Felix Held04be2dd2018-07-29 04:53:22 +02001210 MCHBAR8(0x124) = info->board_lane_delay[4] +
1211 ((frequency_01(info) + 999) / 1000);
1212 MCHBAR16(0x125) = 0x1360;
1213 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001215 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001216 high_multiplier = 1;
1217 some_delay_2_half_cycles = ps_to_halfcycles(info,
1218 ((3 *
1219 fsbcycle_ps(info))
1220 >> 1) +
1221 (halfcycle_ps(info)
1222 *
1223 reg178_min[info->
1224 clock_speed_index]
1225 >> 6)
1226 +
1227 4 *
1228 halfcycle_ps(info)
1229 + 2230);
1230 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001231 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001232 (frequency_11(info) * 2) * (28 -
1233 some_delay_2_half_cycles) /
1234 (frequency_11(info) * 2 -
1235 4 * (info->fsb_frequency))) >> 3, 7);
1236 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001237 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001238 some_delay_3_half_cycles = 3;
1239 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001240 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1241 MCHBAR32(0x224 + (channel << 10)) =
1242 (info->max_slots_used_in_channel - 1) |
1243 ((info->cas_latency - 5 - info->clock_speed_index)
1244 << 21) | ((info->max_slots_used_in_channel +
1245 info->cas_latency - cas_latency_shift - 4) << 16) |
1246 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1247 ((info->cas_latency - info->clock_speed_index +
1248 info->max_slots_used_in_channel - 6) << 8);
1249 MCHBAR32(0x228 + (channel << 10)) =
1250 info->max_slots_used_in_channel;
1251 MCHBAR8(0x239 + (channel << 10)) = 32;
1252 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1253 (some_delay_3_half_cycles << 25) | 0x840000;
1254 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1255 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1256 MCHBAR32(0x24c + (channel << 10)) =
1257 ((!!info->clock_speed_index) << 17) |
1258 (((2 + info->clock_speed_index -
1259 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260
Felix Held04be2dd2018-07-29 04:53:22 +02001261 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1262 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1263 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001264
1265 write_500(info, channel,
1266 ((!info->populated_ranks[channel][1][1])
1267 | (!info->populated_ranks[channel][1][0] << 1)
1268 | (!info->populated_ranks[channel][0][1] << 2)
1269 | (!info->populated_ranks[channel][0][0] << 3)),
1270 0x4c9, 4, 1);
1271 }
1272
Felix Held22ca8cb2018-07-29 05:09:44 +02001273 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274 {
1275 u8 freq_divisor = 2;
1276 if (info->fsb_frequency == frequency_11(info))
1277 freq_divisor = 3;
1278 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1279 freq_divisor = 1;
1280 else
1281 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001282 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001283 }
1284
1285 if (info->board_lane_delay[3] <= 10) {
1286 if (info->board_lane_delay[3] <= 8)
1287 lane_3_delay = info->board_lane_delay[3];
1288 else
1289 lane_3_delay = 10;
1290 } else {
1291 lane_3_delay = 12;
1292 }
1293 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1294 if (info->clock_speed_index > 1)
1295 cas_latency_derived++;
1296 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001297 MCHBAR32(0x240 + (channel << 10)) =
1298 ((info->clock_speed_index == 0) * 0x11000) |
1299 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1300 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001301 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1302 0x609, 6, 1);
1303 write_500(info, channel,
1304 info->clock_speed_index + 2 * info->cas_latency - 7,
1305 0x601, 6, 1);
1306
Felix Held04be2dd2018-07-29 04:53:22 +02001307 MCHBAR32(0x250 + (channel << 10)) =
1308 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1309 (info->board_lane_delay[7] << 2) |
1310 (info->board_lane_delay[4] << 16) |
1311 (info->board_lane_delay[1] << 25) |
1312 (info->board_lane_delay[1] << 29) | 1;
1313 MCHBAR32(0x254 + (channel << 10)) =
1314 (info->board_lane_delay[1] >> 3) |
1315 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1316 0x80 | (info->board_lane_delay[6] << 1) |
1317 (info->board_lane_delay[2] << 28) |
1318 (cas_latency_derived << 16) | 0x4700000;
1319 MCHBAR32(0x258 + (channel << 10)) =
1320 ((info->board_lane_delay[5] + info->clock_speed_index +
1321 9) << 12) | ((info->clock_speed_index -
1322 info->cas_latency + 12) << 8) |
1323 (info->board_lane_delay[2] << 17) |
1324 (info->board_lane_delay[4] << 24) | 0x47;
1325 MCHBAR32(0x25c + (channel << 10)) =
1326 (info->board_lane_delay[1] << 1) |
1327 (info->board_lane_delay[0] << 8) | 0x1da50000;
1328 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1329 MCHBAR8(0x5f8 + (channel << 10)) =
1330 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001331 }
1332
1333 program_modules_memory_map(info, 1);
1334
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001335 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001336 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1337 MCHBAR16_OR(0x612, 0x100);
1338 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 for (i = 0; i < 8; i++) {
Angel Pons3ab19b32020-07-22 16:29:54 +02001340 pci_write_config32(QPI_SAD, 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341 (info->total_memory_mb - 64) | !i | 2);
Angel Pons3ab19b32020-07-22 16:29:54 +02001342 pci_write_config32(QPI_SAD, 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001343 }
1344}
1345
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001346#define DEFAULT_PCI_MMIO_SIZE 2048
1347#define HOST_BRIDGE PCI_DEVFN(0, 0)
1348
1349static unsigned int get_mmio_size(void)
1350{
1351 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001352 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001353
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001354 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001355 if (dev)
1356 cfg = dev->chip_info;
1357
1358 /* If this is zero, it just means devicetree.cb didn't set it */
1359 if (!cfg || cfg->pci_mmio_size == 0)
1360 return DEFAULT_PCI_MMIO_SIZE;
1361 else
1362 return cfg->pci_mmio_size;
1363}
1364
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001365static void program_total_memory_map(struct raminfo *info)
1366{
Angel Pons9333b742020-07-22 16:04:15 +02001367 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001368 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001369 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001370 unsigned int uma_base_igd;
1371 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001372 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001373 int memory_remap;
1374 unsigned int memory_map[8];
1375 int i;
1376 unsigned int current_limit;
1377 unsigned int tseg_base;
1378 int uma_size_igd = 0, uma_size_gtt = 0;
1379
1380 memset(memory_map, 0, sizeof(memory_map));
1381
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001382 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001383 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001384 gav(t);
1385 const int uma_sizes_gtt[16] =
1386 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1387 /* Igd memory */
1388 const int uma_sizes_igd[16] = {
1389 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1390 256, 512
1391 };
1392
1393 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1394 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1395 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001396
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001397 mmio_size = get_mmio_size();
1398
Angel Pons9333b742020-07-22 16:04:15 +02001399 tom = info->total_memory_mb;
1400 if (tom == 4096)
1401 tom = 4032;
1402 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1403 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1404 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001406 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001407 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001408 remap_base = MAX(4096, touud);
1409 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001410 }
Angel Pons9333b742020-07-22 16:04:15 +02001411 if (touud > 4096)
1412 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001413 quickpath_reserved = 0;
1414
Angel Pons3ab19b32020-07-22 16:29:54 +02001415 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001416
Jacob Garber975a7e32019-06-10 16:32:47 -06001417 gav(t);
1418
1419 if (t & 0x800) {
1420 u32 shift = t >> 20;
1421 if (shift == 0)
1422 die("Quickpath value is 0\n");
1423 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001425
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001427 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001428
Angel Pons9333b742020-07-22 16:04:15 +02001429 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001430 uma_base_gtt = uma_base_igd - uma_size_gtt;
1431 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1432 if (!memory_remap)
1433 tseg_base -= quickpath_reserved;
1434 tseg_base = ALIGN_DOWN(tseg_base, 8);
1435
Angel Pons16fe1e02020-07-22 16:12:33 +02001436 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1437 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001439 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1440 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001441 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001442 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443
1444 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001445 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1446 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001448 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449
1450 current_limit = 0;
1451 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1452 memory_map[1] = 4096;
1453 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001454 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons3ab19b32020-07-22 16:29:54 +02001455 pci_write_config32(QPI_SAD, 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1457 1, 64) | 2);
Angel Pons3ab19b32020-07-22 16:29:54 +02001458 pci_write_config32(QPI_SAD, 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459 }
1460}
1461
1462static void collect_system_info(struct raminfo *info)
1463{
1464 u32 capid0[3];
1465 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001466 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467
1468 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001469 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1470 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471
1472 if (!info->heci_bar)
1473 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001474 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001475 if (!info->memory_reserved_for_heci_mb) {
1476 /* Wait for ME to be ready */
1477 intel_early_me_init();
1478 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1479 }
1480
1481 for (i = 0; i < 3; i++)
1482 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001483 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001484 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001485 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1486
1487 if ((capid0[1] >> 11) & 1)
1488 info->uma_enabled = 0;
1489 else
1490 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001491 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001492 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1493 info->silicon_revision = 0;
1494
1495 if (capid0[2] & 2) {
1496 info->silicon_revision = 0;
1497 info->max_supported_clock_speed_index = 2;
1498 for (channel = 0; channel < NUM_CHANNELS; channel++)
1499 if (info->populated_ranks[channel][0][0]
1500 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1501 3) {
1502 info->silicon_revision = 2;
1503 info->max_supported_clock_speed_index = 1;
1504 }
1505 } else {
1506 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1507 case 1:
1508 case 2:
1509 info->silicon_revision = 3;
1510 break;
1511 case 3:
1512 info->silicon_revision = 0;
1513 break;
1514 case 0:
1515 info->silicon_revision = 2;
1516 break;
1517 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001518 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001519 case 0x40:
1520 info->silicon_revision = 0;
1521 break;
1522 case 0x48:
1523 info->silicon_revision = 1;
1524 break;
1525 }
1526 }
1527}
1528
1529static void write_training_data(struct raminfo *info)
1530{
1531 int tm, channel, slot, rank, lane;
1532 if (info->revision < 8)
1533 return;
1534
1535 for (tm = 0; tm < 4; tm++)
1536 for (channel = 0; channel < NUM_CHANNELS; channel++)
1537 for (slot = 0; slot < NUM_SLOTS; slot++)
1538 for (rank = 0; rank < NUM_RANKS; rank++)
1539 for (lane = 0; lane < 9; lane++)
1540 write_500(info, channel,
1541 info->
1542 cached_training->
1543 lane_timings[tm]
1544 [channel][slot][rank]
1545 [lane],
1546 get_timing_register_addr
1547 (lane, tm, slot,
1548 rank), 9, 0);
1549 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1550 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1551}
1552
1553static void dump_timings(struct raminfo *info)
1554{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001555 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001556 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001558 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559 slot, rank);
1560 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001561 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001562 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001563 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001564 read_500(info, channel,
1565 get_timing_register_addr
1566 (lane, i, slot, rank),
1567 9),
1568 info->training.
1569 lane_timings[i][channel][slot][rank]
1570 [lane]);
1571 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001572 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573 }
1574 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001575 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001576 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001577 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579}
1580
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001581/* Read timings and other registers that need to be restored verbatim and
1582 put them to CBMEM.
1583 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001584static void save_timings(struct raminfo *info)
1585{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001587 int channel, slot, rank, lane, i;
1588
1589 train = info->training;
1590 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1591 for (i = 0; i < 4; i++)
1592 train.lane_timings[i][channel][slot][rank][lane] =
1593 read_500(info, channel,
1594 get_timing_register_addr(lane, i, slot,
1595 rank), 9);
1596 train.reg_178 = read_1d0(0x178, 7);
1597 train.reg_10b = read_1d0(0x10b, 6);
1598
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001599 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1600 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001601 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001602 train.reg274265[channel][0] = reg32 >> 16;
1603 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001604 train.reg274265[channel][2] =
1605 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001606 }
Felix Held04be2dd2018-07-29 04:53:22 +02001607 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1608 train.reg_6dc = MCHBAR32(0x6dc);
1609 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001610
Arthur Heymansb3282092019-04-14 17:53:28 +02001611 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1612 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001613
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001614 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001615 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1616 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001617}
1618
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001619static const struct ram_training *get_cached_training(void)
1620{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001621 struct region_device rdev;
1622 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1623 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001624 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001625 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001627
1628/* FIXME: add timeout. */
1629static void wait_heci_ready(void)
1630{
Felix Held04be2dd2018-07-29 04:53:22 +02001631 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1632 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001633 write32((DEFAULT_HECIBAR + 0x4),
1634 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001635}
1636
1637/* FIXME: add timeout. */
1638static void wait_heci_cb_avail(int len)
1639{
1640 union {
1641 struct mei_csr csr;
1642 u32 raw;
1643 } csr;
1644
Felix Held22ca8cb2018-07-29 05:09:44 +02001645 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1646 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647
1648 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001649 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650 while (len >
1651 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001652 csr.csr.buffer_read_ptr))
1653 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001654}
1655
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001656static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001657{
1658 int len = (head->length + 3) / 4;
1659 int i;
1660
1661 wait_heci_cb_avail(len + 1);
1662
1663 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001664 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001666 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001668 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1669 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670}
1671
1672static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001673send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001674{
1675 struct mei_header head;
1676 int maxlen;
1677
1678 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680
1681 while (len) {
1682 int cur = len;
1683 if (cur > maxlen) {
1684 cur = maxlen;
1685 head.is_complete = 0;
1686 } else
1687 head.is_complete = 1;
1688 head.length = cur;
1689 head.reserved = 0;
1690 head.client_address = clientaddress;
1691 head.host_address = hostaddress;
1692 send_heci_packet(&head, (u32 *) msg);
1693 len -= cur;
1694 msg += cur;
1695 }
1696}
1697
1698/* FIXME: Add timeout. */
1699static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001700recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1701 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001702{
1703 union {
1704 struct mei_csr csr;
1705 u32 raw;
1706 } csr;
1707 int i = 0;
1708
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001709 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001711 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001712 }
Felix Held04be2dd2018-07-29 04:53:22 +02001713 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1714 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001715 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001717 write32(DEFAULT_HECIBAR + 0x4,
1718 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001719 *packet_size = 0;
1720 return 0;
1721 }
1722 if (head->length + 4 > 4 * csr.csr.buffer_depth
1723 || head->length > *packet_size) {
1724 *packet_size = 0;
1725 return -1;
1726 }
1727
1728 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001730 while (((head->length + 3) >> 2) >
1731 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1732 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733
1734 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001735 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001736 *packet_size = head->length;
1737 if (!csr.csr.ready)
1738 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001739 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740 return 0;
1741}
1742
1743/* FIXME: Add timeout. */
1744static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001745recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746{
1747 struct mei_header head;
1748 int current_position;
1749
1750 current_position = 0;
1751 while (1) {
1752 u32 current_size;
1753 current_size = *message_size - current_position;
1754 if (recv_heci_packet
1755 (info, &head, message + (current_position >> 2),
1756 &current_size) == -1)
1757 break;
1758 if (!current_size)
1759 break;
1760 current_position += current_size;
1761 if (head.is_complete) {
1762 *message_size = current_position;
1763 return 0;
1764 }
1765
1766 if (current_position >= *message_size)
1767 break;
1768 }
1769 *message_size = 0;
1770 return -1;
1771}
1772
1773static void send_heci_uma_message(struct raminfo *info)
1774{
1775 struct uma_reply {
1776 u8 group_id;
1777 u8 command;
1778 u8 reserved;
1779 u8 result;
1780 u8 field2;
1781 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001782 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001783
1784 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1785 reply.command = 0;
1786
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001787 struct uma_message {
1788 u8 group_id;
1789 u8 cmd;
1790 u8 reserved;
1791 u8 result;
1792 u32 c2;
1793 u64 heci_uma_addr;
1794 u32 memory_reserved_for_heci_mb;
1795 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001796 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001797 0, MKHI_SET_UMA, 0, 0,
1798 0x82,
1799 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1800 u32 reply_size;
1801
1802 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1803
1804 reply_size = sizeof(reply);
1805 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1806 return;
1807
1808 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1809 die("HECI init failed\n");
1810}
1811
1812static void setup_heci_uma(struct raminfo *info)
1813{
1814 u32 reg44;
1815
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001816 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001817 info->memory_reserved_for_heci_mb = 0;
1818 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001819 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001820 return;
1821
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001822 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001823 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1824 info->heci_uma_addr =
1825 ((u64)
Angel Pons16fe1e02020-07-22 16:12:33 +02001826 ((((u64) pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827 info->memory_reserved_for_heci_mb)) << 20;
1828
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001829 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001830 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001831 write32(DEFAULT_DMIBAR + 0x14,
1832 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1833 write32(DEFAULT_RCBA + 0x14,
1834 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1835 write32(DEFAULT_DMIBAR + 0x20,
1836 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1837 write32(DEFAULT_RCBA + 0x20,
1838 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1839 write32(DEFAULT_DMIBAR + 0x2c,
1840 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1841 write32(DEFAULT_RCBA + 0x30,
1842 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1843 write32(DEFAULT_DMIBAR + 0x38,
1844 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1845 write32(DEFAULT_RCBA + 0x40,
1846 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001848 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1849 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001850 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1851 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1852 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001853 }
1854
Felix Held04be2dd2018-07-29 04:53:22 +02001855 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001856
1857 send_heci_uma_message(info);
1858
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001859 pci_write_config32(HECIDEV, 0x10, 0x0);
1860 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001861
1862}
1863
1864static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1865{
1866 int ranks_in_channel;
1867 ranks_in_channel = info->populated_ranks[channel][0][0]
1868 + info->populated_ranks[channel][0][1]
1869 + info->populated_ranks[channel][1][0]
1870 + info->populated_ranks[channel][1][1];
1871
1872 /* empty channel */
1873 if (ranks_in_channel == 0)
1874 return 1;
1875
1876 if (ranks_in_channel != ranks)
1877 return 0;
1878 /* single slot */
1879 if (info->populated_ranks[channel][0][0] !=
1880 info->populated_ranks[channel][1][0])
1881 return 1;
1882 if (info->populated_ranks[channel][0][1] !=
1883 info->populated_ranks[channel][1][1])
1884 return 1;
1885 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1886 return 0;
1887 if (info->density[channel][0] != info->density[channel][1])
1888 return 0;
1889 return 1;
1890}
1891
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001892static void read_4090(struct raminfo *info)
1893{
1894 int i, channel, slot, rank, lane;
1895 for (i = 0; i < 2; i++)
1896 for (slot = 0; slot < NUM_SLOTS; slot++)
1897 for (rank = 0; rank < NUM_RANKS; rank++)
1898 for (lane = 0; lane < 9; lane++)
1899 info->training.
1900 lane_timings[0][i][slot][rank][lane]
1901 = 32;
1902
1903 for (i = 1; i < 4; i++)
1904 for (channel = 0; channel < NUM_CHANNELS; channel++)
1905 for (slot = 0; slot < NUM_SLOTS; slot++)
1906 for (rank = 0; rank < NUM_RANKS; rank++)
1907 for (lane = 0; lane < 9; lane++) {
1908 info->training.
1909 lane_timings[i][channel]
1910 [slot][rank][lane] =
1911 read_500(info, channel,
1912 get_timing_register_addr
1913 (lane, i, slot,
1914 rank), 9)
1915 + (i == 1) * 11; // !!!!
1916 }
1917
1918}
1919
1920static u32 get_etalon2(int flip, u32 addr)
1921{
1922 const u16 invmask[] = {
1923 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1924 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1925 };
1926 u32 ret;
1927 u32 comp4 = addr / 480;
1928 addr %= 480;
1929 u32 comp1 = addr & 0xf;
1930 u32 comp2 = (addr >> 4) & 1;
1931 u32 comp3 = addr >> 5;
1932
1933 if (comp4)
1934 ret = 0x1010101 << (comp4 - 1);
1935 else
1936 ret = 0;
1937 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1938 ret = ~ret;
1939
1940 return ret;
1941}
1942
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001943static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001944{
1945 msr_t msr = {.lo = 0, .hi = 0 };
1946
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001947 wrmsr(MTRR_PHYS_BASE(3), msr);
1948 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001949}
1950
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001951static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001952{
1953 msr_t msr;
1954 msr.lo = base | MTRR_TYPE_WRPROT;
1955 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001956 wrmsr(MTRR_PHYS_BASE(3), msr);
1957 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958 & 0xffffffff);
1959 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001960 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001961}
1962
1963static void flush_cache(u32 start, u32 size)
1964{
1965 u32 end;
1966 u32 addr;
1967
1968 end = start + (ALIGN_DOWN(size + 4096, 4096));
1969 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001970 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001971}
1972
1973static void clear_errors(void)
1974{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001975 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001976}
1977
1978static void write_testing(struct raminfo *info, int totalrank, int flip)
1979{
1980 int nwrites = 0;
1981 /* in 8-byte units. */
1982 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001983 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001984
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001985 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001986 for (offset = 0; offset < 9 * 480; offset += 2) {
1987 write32(base + offset * 8, get_etalon2(flip, offset));
1988 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1989 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1990 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1991 nwrites += 4;
1992 if (nwrites >= 320) {
1993 clear_errors();
1994 nwrites = 0;
1995 }
1996 }
1997}
1998
1999static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2000{
2001 u8 failmask = 0;
2002 int i;
2003 int comp1, comp2, comp3;
2004 u32 failxor[2] = { 0, 0 };
2005
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002006 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002007
2008 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2009 for (comp1 = 0; comp1 < 4; comp1++)
2010 for (comp2 = 0; comp2 < 60; comp2++) {
2011 u32 re[4];
2012 u32 curroffset =
2013 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2014 read128((total_rank << 28) | (curroffset << 3),
2015 (u64 *) re);
2016 failxor[0] |=
2017 get_etalon2(flip, curroffset) ^ re[0];
2018 failxor[1] |=
2019 get_etalon2(flip, curroffset) ^ re[1];
2020 failxor[0] |=
2021 get_etalon2(flip, curroffset | 1) ^ re[2];
2022 failxor[1] |=
2023 get_etalon2(flip, curroffset | 1) ^ re[3];
2024 }
2025 for (i = 0; i < 8; i++)
2026 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2027 failmask |= 1 << i;
2028 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002029 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002030 flush_cache((total_rank << 28), 1728 * 5 * 4);
2031 return failmask;
2032}
2033
2034const u32 seed1[0x18] = {
2035 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2036 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2037 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2038 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2039 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2040 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2041};
2042
2043static u32 get_seed2(int a, int b)
2044{
2045 const u32 seed2[5] = {
2046 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2047 0x5b6db6db,
2048 };
2049 u32 r;
2050 r = seed2[(a + (a >= 10)) / 5];
2051 return b ? ~r : r;
2052}
2053
2054static int make_shift(int comp2, int comp5, int x)
2055{
2056 const u8 seed3[32] = {
2057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2058 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2059 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2060 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2061 };
2062
2063 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2064}
2065
2066static u32 get_etalon(int flip, u32 addr)
2067{
2068 u32 mask_byte = 0;
2069 int comp1 = (addr >> 1) & 1;
2070 int comp2 = (addr >> 3) & 0x1f;
2071 int comp3 = (addr >> 8) & 0xf;
2072 int comp4 = (addr >> 12) & 0xf;
2073 int comp5 = (addr >> 16) & 0x1f;
2074 u32 mask_bit = ~(0x10001 << comp3);
2075 u32 part1;
2076 u32 part2;
2077 int byte;
2078
2079 part2 =
2080 ((seed1[comp5] >>
2081 make_shift(comp2, comp5,
2082 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2083 part1 =
2084 ((seed1[comp5] >>
2085 make_shift(comp2, comp5,
2086 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2087
2088 for (byte = 0; byte < 4; byte++)
2089 if ((get_seed2(comp5, comp4) >>
2090 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2091 mask_byte |= 0xff << (8 * byte);
2092
2093 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2094 (comp3 + 16));
2095}
2096
2097static void
2098write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2099 char flip)
2100{
2101 int i;
2102 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002103 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2104 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002105}
2106
2107static u8
2108check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2109 char flip)
2110{
2111 u8 failmask = 0;
2112 u32 failxor[2];
2113 int i;
2114 int comp1, comp2, comp3;
2115
2116 failxor[0] = 0;
2117 failxor[1] = 0;
2118
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002119 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002120 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2121 for (comp1 = 0; comp1 < 16; comp1++)
2122 for (comp2 = 0; comp2 < 64; comp2++) {
2123 u32 addr =
2124 (totalrank << 28) | (region << 25) | (block
2125 << 16)
2126 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2127 2);
2128 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002129 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002130 }
2131 for (i = 0; i < 8; i++)
2132 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2133 failmask |= 1 << i;
2134 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002135 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002136 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2137 return failmask;
2138}
2139
2140static int check_bounded(unsigned short *vals, u16 bound)
2141{
2142 int i;
2143
2144 for (i = 0; i < 8; i++)
2145 if (vals[i] < bound)
2146 return 0;
2147 return 1;
2148}
2149
2150enum state {
2151 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2152};
2153
2154static int validate_state(enum state *in)
2155{
2156 int i;
2157 for (i = 0; i < 8; i++)
2158 if (in[i] != COMPLETE)
2159 return 0;
2160 return 1;
2161}
2162
2163static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002164do_fsm(enum state *state, u16 *counter,
2165 u8 fail_mask, int margin, int uplimit,
2166 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002167{
2168 int lane;
2169
2170 for (lane = 0; lane < 8; lane++) {
2171 int is_fail = (fail_mask >> lane) & 1;
2172 switch (state[lane]) {
2173 case BEFORE_USABLE:
2174 if (!is_fail) {
2175 counter[lane] = 1;
2176 state[lane] = AT_USABLE;
2177 break;
2178 }
2179 counter[lane] = 0;
2180 state[lane] = BEFORE_USABLE;
2181 break;
2182 case AT_USABLE:
2183 if (!is_fail) {
2184 ++counter[lane];
2185 if (counter[lane] >= margin) {
2186 state[lane] = AT_MARGIN;
2187 res_low[lane] = val - margin + 1;
2188 break;
2189 }
2190 state[lane] = 1;
2191 break;
2192 }
2193 counter[lane] = 0;
2194 state[lane] = BEFORE_USABLE;
2195 break;
2196 case AT_MARGIN:
2197 if (is_fail) {
2198 state[lane] = COMPLETE;
2199 res_high[lane] = val - 1;
2200 } else {
2201 counter[lane]++;
2202 state[lane] = AT_MARGIN;
2203 if (val == uplimit) {
2204 state[lane] = COMPLETE;
2205 res_high[lane] = uplimit;
2206 }
2207 }
2208 break;
2209 case COMPLETE:
2210 break;
2211 }
2212 }
2213}
2214
2215static void
2216train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2217 u8 total_rank, u8 reg_178, int first_run, int niter,
2218 timing_bounds_t * timings)
2219{
2220 int lane;
2221 enum state state[8];
2222 u16 count[8];
2223 u8 lower_usable[8];
2224 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002225 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002226 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002227 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002228
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002229 for (i = 0; i < 8; i++)
2230 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002231
2232 if (!first_run) {
2233 int is_all_ok = 1;
2234 for (lane = 0; lane < 8; lane++)
2235 if (timings[reg_178][channel][slot][rank][lane].
2236 smallest ==
2237 timings[reg_178][channel][slot][rank][lane].
2238 largest) {
2239 timings[reg_178][channel][slot][rank][lane].
2240 smallest = 0;
2241 timings[reg_178][channel][slot][rank][lane].
2242 largest = 0;
2243 is_all_ok = 0;
2244 }
2245 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002246 for (i = 0; i < 8; i++)
2247 state[i] = COMPLETE;
2248 }
2249 }
2250
2251 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2252 u8 failmask = 0;
2253 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2254 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2255 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002256 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002257 do_fsm(state, count, failmask, 5, 47, lower_usable,
2258 upper_usable, reg1b3);
2259 }
2260
2261 if (reg1b3) {
2262 write_1d0(0, 0x1b3, 6, 1);
2263 write_1d0(0, 0x1a3, 6, 1);
2264 for (lane = 0; lane < 8; lane++) {
2265 if (state[lane] == COMPLETE) {
2266 timings[reg_178][channel][slot][rank][lane].
2267 smallest =
2268 lower_usable[lane] +
2269 (info->training.
2270 lane_timings[0][channel][slot][rank][lane]
2271 & 0x3F) - 32;
2272 timings[reg_178][channel][slot][rank][lane].
2273 largest =
2274 upper_usable[lane] +
2275 (info->training.
2276 lane_timings[0][channel][slot][rank][lane]
2277 & 0x3F) - 32;
2278 }
2279 }
2280 }
2281
2282 if (!first_run) {
2283 for (lane = 0; lane < 8; lane++)
2284 if (state[lane] == COMPLETE) {
2285 write_500(info, channel,
2286 timings[reg_178][channel][slot][rank]
2287 [lane].smallest,
2288 get_timing_register_addr(lane, 0,
2289 slot, rank),
2290 9, 1);
2291 write_500(info, channel,
2292 timings[reg_178][channel][slot][rank]
2293 [lane].smallest +
2294 info->training.
2295 lane_timings[1][channel][slot][rank]
2296 [lane]
2297 -
2298 info->training.
2299 lane_timings[0][channel][slot][rank]
2300 [lane], get_timing_register_addr(lane,
2301 1,
2302 slot,
2303 rank),
2304 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002307 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308
2309 do {
2310 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002311 for (i = 0; i < niter; i++) {
2312 if (failmask == 0xFF)
2313 break;
2314 failmask |=
2315 check_testing_type2(info, total_rank, 2, i,
2316 0);
2317 failmask |=
2318 check_testing_type2(info, total_rank, 3, i,
2319 1);
2320 }
Felix Held04be2dd2018-07-29 04:53:22 +02002321 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002323 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002324 if ((1 << lane) & failmask) {
2325 if (timings[reg_178][channel]
2326 [slot][rank][lane].
2327 largest <=
2328 timings[reg_178][channel]
2329 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002330 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002331 [lane] = -1;
2332 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002333 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334 [lane] = 0;
2335 timings[reg_178]
2336 [channel][slot]
2337 [rank][lane].
2338 smallest++;
2339 write_500(info, channel,
2340 timings
2341 [reg_178]
2342 [channel]
2343 [slot][rank]
2344 [lane].
2345 smallest,
2346 get_timing_register_addr
2347 (lane, 0,
2348 slot, rank),
2349 9, 1);
2350 write_500(info, channel,
2351 timings
2352 [reg_178]
2353 [channel]
2354 [slot][rank]
2355 [lane].
2356 smallest +
2357 info->
2358 training.
2359 lane_timings
2360 [1][channel]
2361 [slot][rank]
2362 [lane]
2363 -
2364 info->
2365 training.
2366 lane_timings
2367 [0][channel]
2368 [slot][rank]
2369 [lane],
2370 get_timing_register_addr
2371 (lane, 1,
2372 slot, rank),
2373 9, 1);
2374 }
2375 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002376 num_successfully_checked[lane]
2377 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002378 }
2379 }
Felix Held04be2dd2018-07-29 04:53:22 +02002380 while (!check_bounded(num_successfully_checked, 2))
2381 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002382
2383 for (lane = 0; lane < 8; lane++)
2384 if (state[lane] == COMPLETE) {
2385 write_500(info, channel,
2386 timings[reg_178][channel][slot][rank]
2387 [lane].largest,
2388 get_timing_register_addr(lane, 0,
2389 slot, rank),
2390 9, 1);
2391 write_500(info, channel,
2392 timings[reg_178][channel][slot][rank]
2393 [lane].largest +
2394 info->training.
2395 lane_timings[1][channel][slot][rank]
2396 [lane]
2397 -
2398 info->training.
2399 lane_timings[0][channel][slot][rank]
2400 [lane], get_timing_register_addr(lane,
2401 1,
2402 slot,
2403 rank),
2404 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002405 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002406 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002407 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002408
2409 do {
2410 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002411 for (i = 0; i < niter; i++) {
2412 if (failmask == 0xFF)
2413 break;
2414 failmask |=
2415 check_testing_type2(info, total_rank, 2, i,
2416 0);
2417 failmask |=
2418 check_testing_type2(info, total_rank, 3, i,
2419 1);
2420 }
2421
Felix Held04be2dd2018-07-29 04:53:22 +02002422 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002424 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002425 if ((1 << lane) & failmask) {
2426 if (timings[reg_178][channel]
2427 [slot][rank][lane].
2428 largest <=
2429 timings[reg_178][channel]
2430 [slot][rank][lane].
2431 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002432 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002433 [lane] = -1;
2434 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002435 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002436 [lane] = 0;
2437 timings[reg_178]
2438 [channel][slot]
2439 [rank][lane].
2440 largest--;
2441 write_500(info, channel,
2442 timings
2443 [reg_178]
2444 [channel]
2445 [slot][rank]
2446 [lane].
2447 largest,
2448 get_timing_register_addr
2449 (lane, 0,
2450 slot, rank),
2451 9, 1);
2452 write_500(info, channel,
2453 timings
2454 [reg_178]
2455 [channel]
2456 [slot][rank]
2457 [lane].
2458 largest +
2459 info->
2460 training.
2461 lane_timings
2462 [1][channel]
2463 [slot][rank]
2464 [lane]
2465 -
2466 info->
2467 training.
2468 lane_timings
2469 [0][channel]
2470 [slot][rank]
2471 [lane],
2472 get_timing_register_addr
2473 (lane, 1,
2474 slot, rank),
2475 9, 1);
2476 }
2477 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002478 num_successfully_checked[lane]
2479 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002480 }
2481 }
2482 }
Felix Held04be2dd2018-07-29 04:53:22 +02002483 while (!check_bounded(num_successfully_checked, 3))
2484 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002485
2486 for (lane = 0; lane < 8; lane++) {
2487 write_500(info, channel,
2488 info->training.
2489 lane_timings[0][channel][slot][rank][lane],
2490 get_timing_register_addr(lane, 0, slot, rank),
2491 9, 1);
2492 write_500(info, channel,
2493 info->training.
2494 lane_timings[1][channel][slot][rank][lane],
2495 get_timing_register_addr(lane, 1, slot, rank),
2496 9, 1);
2497 if (timings[reg_178][channel][slot][rank][lane].
2498 largest <=
2499 timings[reg_178][channel][slot][rank][lane].
2500 smallest) {
2501 timings[reg_178][channel][slot][rank][lane].
2502 largest = 0;
2503 timings[reg_178][channel][slot][rank][lane].
2504 smallest = 0;
2505 }
2506 }
2507 }
2508}
2509
2510static void set_10b(struct raminfo *info, u8 val)
2511{
2512 int channel;
2513 int slot, rank;
2514 int lane;
2515
2516 if (read_1d0(0x10b, 6) == val)
2517 return;
2518
2519 write_1d0(val, 0x10b, 6, 1);
2520
2521 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2522 u16 reg_500;
2523 reg_500 = read_500(info, channel,
2524 get_timing_register_addr(lane, 0, slot,
2525 rank), 9);
2526 if (val == 1) {
2527 if (lut16[info->clock_speed_index] <= reg_500)
2528 reg_500 -= lut16[info->clock_speed_index];
2529 else
2530 reg_500 = 0;
2531 } else {
2532 reg_500 += lut16[info->clock_speed_index];
2533 }
2534 write_500(info, channel, reg_500,
2535 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2536 }
2537}
2538
2539static void set_ecc(int onoff)
2540{
2541 int channel;
2542 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2543 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002544 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002545 if (onoff)
2546 t |= 1;
2547 else
2548 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002549 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002550 }
2551}
2552
2553static void set_178(u8 val)
2554{
2555 if (val >= 31)
2556 val = val - 31;
2557 else
2558 val = 63 - val;
2559
2560 write_1d0(2 * val, 0x178, 7, 1);
2561}
2562
2563static void
2564write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2565 int type)
2566{
2567 int lane;
2568
2569 for (lane = 0; lane < 8; lane++)
2570 write_500(info, channel,
2571 info->training.
2572 lane_timings[type][channel][slot][rank][lane],
2573 get_timing_register_addr(lane, type, slot, rank), 9,
2574 0);
2575}
2576
2577static void
2578try_timing_offsets(struct raminfo *info, int channel,
2579 int slot, int rank, int totalrank)
2580{
2581 u16 count[8];
2582 enum state state[8];
2583 u8 lower_usable[8], upper_usable[8];
2584 int lane;
2585 int i;
2586 int flip = 1;
2587 int timing_offset;
2588
2589 for (i = 0; i < 8; i++)
2590 state[i] = BEFORE_USABLE;
2591
2592 memset(count, 0, sizeof(count));
2593
2594 for (lane = 0; lane < 8; lane++)
2595 write_500(info, channel,
2596 info->training.
2597 lane_timings[2][channel][slot][rank][lane] + 32,
2598 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2599
2600 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2601 timing_offset++) {
2602 u8 failmask;
2603 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2604 failmask = 0;
2605 for (i = 0; i < 2 && failmask != 0xff; i++) {
2606 flip = !flip;
2607 write_testing(info, totalrank, flip);
2608 failmask |= check_testing(info, totalrank, flip);
2609 }
2610 do_fsm(state, count, failmask, 10, 63, lower_usable,
2611 upper_usable, timing_offset);
2612 }
2613 write_1d0(0, 0x1bb, 6, 1);
2614 dump_timings(info);
2615 if (!validate_state(state))
2616 die("Couldn't discover DRAM timings (1)\n");
2617
2618 for (lane = 0; lane < 8; lane++) {
2619 u8 bias = 0;
2620
2621 if (info->silicon_revision) {
2622 int usable_length;
2623
2624 usable_length = upper_usable[lane] - lower_usable[lane];
2625 if (usable_length >= 20) {
2626 bias = usable_length / 2 - 10;
2627 if (bias >= 2)
2628 bias = 2;
2629 }
2630 }
2631 write_500(info, channel,
2632 info->training.
2633 lane_timings[2][channel][slot][rank][lane] +
2634 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2635 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2636 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2637 info->training.lane_timings[2][channel][slot][rank][lane] +
2638 lower_usable[lane];
2639 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2640 info->training.lane_timings[2][channel][slot][rank][lane] +
2641 upper_usable[lane];
2642 info->training.timing2_offset[channel][slot][rank][lane] =
2643 info->training.lane_timings[2][channel][slot][rank][lane];
2644 }
2645}
2646
2647static u8
2648choose_training(struct raminfo *info, int channel, int slot, int rank,
2649 int lane, timing_bounds_t * timings, u8 center_178)
2650{
2651 u16 central_weight;
2652 u16 side_weight;
2653 unsigned int sum = 0, count = 0;
2654 u8 span;
2655 u8 lower_margin, upper_margin;
2656 u8 reg_178;
2657 u8 result;
2658
2659 span = 12;
2660 central_weight = 20;
2661 side_weight = 20;
2662 if (info->silicon_revision == 1 && channel == 1) {
2663 central_weight = 5;
2664 side_weight = 20;
2665 if ((info->
2666 populated_ranks_mask[1] ^ (info->
2667 populated_ranks_mask[1] >> 2)) &
2668 1)
2669 span = 18;
2670 }
2671 if ((info->populated_ranks_mask[0] & 5) == 5) {
2672 central_weight = 20;
2673 side_weight = 20;
2674 }
2675 if (info->clock_speed_index >= 2
2676 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2677 if (info->silicon_revision == 1) {
2678 switch (channel) {
2679 case 0:
2680 if (lane == 1) {
2681 central_weight = 10;
2682 side_weight = 20;
2683 }
2684 break;
2685 case 1:
2686 if (lane == 6) {
2687 side_weight = 5;
2688 central_weight = 20;
2689 }
2690 break;
2691 }
2692 }
2693 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2694 side_weight = 5;
2695 central_weight = 20;
2696 }
2697 }
2698 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2699 reg_178 += span) {
2700 u8 smallest;
2701 u8 largest;
2702 largest = timings[reg_178][channel][slot][rank][lane].largest;
2703 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2704 if (largest - smallest + 1 >= 5) {
2705 unsigned int weight;
2706 if (reg_178 == center_178)
2707 weight = central_weight;
2708 else
2709 weight = side_weight;
2710 sum += weight * (largest + smallest);
2711 count += weight;
2712 }
2713 }
2714 dump_timings(info);
2715 if (count == 0)
2716 die("Couldn't discover DRAM timings (2)\n");
2717 result = sum / (2 * count);
2718 lower_margin =
2719 result - timings[center_178][channel][slot][rank][lane].smallest;
2720 upper_margin =
2721 timings[center_178][channel][slot][rank][lane].largest - result;
2722 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002723 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002724 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002725 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002726 return result;
2727}
2728
2729#define STANDARD_MIN_MARGIN 5
2730
2731static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2732{
2733 u16 margin[64];
2734 int lane, rank, slot, channel;
2735 u8 reg178;
2736 int count = 0, sum = 0;
2737
2738 for (reg178 = reg178_min[info->clock_speed_index];
2739 reg178 < reg178_max[info->clock_speed_index];
2740 reg178 += reg178_step[info->clock_speed_index]) {
2741 margin[reg178] = -1;
2742 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2743 int curmargin =
2744 timings[reg178][channel][slot][rank][lane].largest -
2745 timings[reg178][channel][slot][rank][lane].
2746 smallest + 1;
2747 if (curmargin < margin[reg178])
2748 margin[reg178] = curmargin;
2749 }
2750 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2751 u16 weight;
2752 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2753 sum += weight * reg178;
2754 count += weight;
2755 }
2756 }
2757 dump_timings(info);
2758 if (count == 0)
2759 die("Couldn't discover DRAM timings (3)\n");
2760
2761 u8 threshold;
2762
2763 for (threshold = 30; threshold >= 5; threshold--) {
2764 int usable_length = 0;
2765 int smallest_fount = 0;
2766 for (reg178 = reg178_min[info->clock_speed_index];
2767 reg178 < reg178_max[info->clock_speed_index];
2768 reg178 += reg178_step[info->clock_speed_index])
2769 if (margin[reg178] >= threshold) {
2770 usable_length +=
2771 reg178_step[info->clock_speed_index];
2772 info->training.reg178_largest =
2773 reg178 -
2774 2 * reg178_step[info->clock_speed_index];
2775
2776 if (!smallest_fount) {
2777 smallest_fount = 1;
2778 info->training.reg178_smallest =
2779 reg178 +
2780 reg178_step[info->
2781 clock_speed_index];
2782 }
2783 }
2784 if (usable_length >= 0x21)
2785 break;
2786 }
2787
2788 return sum / count;
2789}
2790
2791static int check_cached_sanity(struct raminfo *info)
2792{
2793 int lane;
2794 int slot, rank;
2795 int channel;
2796
2797 if (!info->cached_training)
2798 return 0;
2799
2800 for (channel = 0; channel < NUM_CHANNELS; channel++)
2801 for (slot = 0; slot < NUM_SLOTS; slot++)
2802 for (rank = 0; rank < NUM_RANKS; rank++)
2803 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2804 u16 cached_value, estimation_value;
2805 cached_value =
2806 info->cached_training->
2807 lane_timings[1][channel][slot][rank]
2808 [lane];
2809 if (cached_value >= 0x18
2810 && cached_value <= 0x1E7) {
2811 estimation_value =
2812 info->training.
2813 lane_timings[1][channel]
2814 [slot][rank][lane];
2815 if (estimation_value <
2816 cached_value - 24)
2817 return 0;
2818 if (estimation_value >
2819 cached_value + 24)
2820 return 0;
2821 }
2822 }
2823 return 1;
2824}
2825
2826static int try_cached_training(struct raminfo *info)
2827{
2828 u8 saved_243[2];
2829 u8 tm;
2830
2831 int channel, slot, rank, lane;
2832 int flip = 1;
2833 int i, j;
2834
2835 if (!check_cached_sanity(info))
2836 return 0;
2837
2838 info->training.reg178_center = info->cached_training->reg178_center;
2839 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2840 info->training.reg178_largest = info->cached_training->reg178_largest;
2841 memcpy(&info->training.timing_bounds,
2842 &info->cached_training->timing_bounds,
2843 sizeof(info->training.timing_bounds));
2844 memcpy(&info->training.timing_offset,
2845 &info->cached_training->timing_offset,
2846 sizeof(info->training.timing_offset));
2847
2848 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002849 saved_243[0] = MCHBAR8(0x243);
2850 saved_243[1] = MCHBAR8(0x643);
2851 MCHBAR8(0x243) = saved_243[0] | 2;
2852 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002853 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002854 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002855 if (read_1d0(0x10b, 6) & 1)
2856 set_10b(info, 0);
2857 for (tm = 0; tm < 2; tm++) {
2858 int totalrank;
2859
2860 set_178(tm ? info->cached_training->reg178_largest : info->
2861 cached_training->reg178_smallest);
2862
2863 totalrank = 0;
2864 /* Check timing ranges. With i == 0 we check smallest one and with
2865 i == 1 the largest bound. With j == 0 we check that on the bound
2866 it still works whereas with j == 1 we check that just outside of
2867 bound we fail.
2868 */
2869 FOR_POPULATED_RANKS_BACKWARDS {
2870 for (i = 0; i < 2; i++) {
2871 for (lane = 0; lane < 8; lane++) {
2872 write_500(info, channel,
2873 info->cached_training->
2874 timing2_bounds[channel][slot]
2875 [rank][lane][i],
2876 get_timing_register_addr(lane,
2877 3,
2878 slot,
2879 rank),
2880 9, 1);
2881
2882 if (!i)
2883 write_500(info, channel,
2884 info->
2885 cached_training->
2886 timing2_offset
2887 [channel][slot][rank]
2888 [lane],
2889 get_timing_register_addr
2890 (lane, 2, slot, rank),
2891 9, 1);
2892 write_500(info, channel,
2893 i ? info->cached_training->
2894 timing_bounds[tm][channel]
2895 [slot][rank][lane].
2896 largest : info->
2897 cached_training->
2898 timing_bounds[tm][channel]
2899 [slot][rank][lane].smallest,
2900 get_timing_register_addr(lane,
2901 0,
2902 slot,
2903 rank),
2904 9, 1);
2905 write_500(info, channel,
2906 info->cached_training->
2907 timing_offset[channel][slot]
2908 [rank][lane] +
2909 (i ? info->cached_training->
2910 timing_bounds[tm][channel]
2911 [slot][rank][lane].
2912 largest : info->
2913 cached_training->
2914 timing_bounds[tm][channel]
2915 [slot][rank][lane].
2916 smallest) - 64,
2917 get_timing_register_addr(lane,
2918 1,
2919 slot,
2920 rank),
2921 9, 1);
2922 }
2923 for (j = 0; j < 2; j++) {
2924 u8 failmask;
2925 u8 expected_failmask;
2926 char reg1b3;
2927
2928 reg1b3 = (j == 1) + 4;
2929 reg1b3 =
2930 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2931 write_1d0(reg1b3, 0x1bb, 6, 1);
2932 write_1d0(reg1b3, 0x1b3, 6, 1);
2933 write_1d0(reg1b3, 0x1a3, 6, 1);
2934
2935 flip = !flip;
2936 write_testing(info, totalrank, flip);
2937 failmask =
2938 check_testing(info, totalrank,
2939 flip);
2940 expected_failmask =
2941 j == 0 ? 0x00 : 0xff;
2942 if (failmask != expected_failmask)
2943 goto fail;
2944 }
2945 }
2946 totalrank++;
2947 }
2948 }
2949
2950 set_178(info->cached_training->reg178_center);
2951 if (info->use_ecc)
2952 set_ecc(1);
2953 write_training_data(info);
2954 write_1d0(0, 322, 3, 1);
2955 info->training = *info->cached_training;
2956
2957 write_1d0(0, 0x1bb, 6, 1);
2958 write_1d0(0, 0x1b3, 6, 1);
2959 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002960 MCHBAR8(0x243) = saved_243[0];
2961 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002962
2963 return 1;
2964
2965fail:
2966 FOR_POPULATED_RANKS {
2967 write_500_timings_type(info, channel, slot, rank, 1);
2968 write_500_timings_type(info, channel, slot, rank, 2);
2969 write_500_timings_type(info, channel, slot, rank, 3);
2970 }
2971
2972 write_1d0(0, 0x1bb, 6, 1);
2973 write_1d0(0, 0x1b3, 6, 1);
2974 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002975 MCHBAR8(0x243) = saved_243[0];
2976 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002977
2978 return 0;
2979}
2980
2981static void do_ram_training(struct raminfo *info)
2982{
2983 u8 saved_243[2];
2984 int totalrank = 0;
2985 u8 reg_178;
2986 int niter;
2987
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002988 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002989 int lane, rank, slot, channel;
2990 u8 reg178_center;
2991
2992 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002993 saved_243[0] = MCHBAR8(0x243);
2994 saved_243[1] = MCHBAR8(0x643);
2995 MCHBAR8(0x243) = saved_243[0] | 2;
2996 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002997 switch (info->clock_speed_index) {
2998 case 0:
2999 niter = 5;
3000 break;
3001 case 1:
3002 niter = 10;
3003 break;
3004 default:
3005 niter = 19;
3006 break;
3007 }
3008 set_ecc(0);
3009
3010 FOR_POPULATED_RANKS_BACKWARDS {
3011 int i;
3012
3013 write_500_timings_type(info, channel, slot, rank, 0);
3014
3015 write_testing(info, totalrank, 0);
3016 for (i = 0; i < niter; i++) {
3017 write_testing_type2(info, totalrank, 2, i, 0);
3018 write_testing_type2(info, totalrank, 3, i, 1);
3019 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003020 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003021 totalrank++;
3022 }
3023
3024 if (reg178_min[info->clock_speed_index] <
3025 reg178_max[info->clock_speed_index])
3026 memset(timings[reg178_min[info->clock_speed_index]], 0,
3027 sizeof(timings[0]) *
3028 (reg178_max[info->clock_speed_index] -
3029 reg178_min[info->clock_speed_index]));
3030 for (reg_178 = reg178_min[info->clock_speed_index];
3031 reg_178 < reg178_max[info->clock_speed_index];
3032 reg_178 += reg178_step[info->clock_speed_index]) {
3033 totalrank = 0;
3034 set_178(reg_178);
3035 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3036 for (slot = 0; slot < NUM_SLOTS; slot++)
3037 for (rank = 0; rank < NUM_RANKS; rank++) {
3038 memset(&timings[reg_178][channel][slot]
3039 [rank][0].smallest, 0, 16);
3040 if (info->
3041 populated_ranks[channel][slot]
3042 [rank]) {
3043 train_ram_at_178(info, channel,
3044 slot, rank,
3045 totalrank,
3046 reg_178, 1,
3047 niter,
3048 timings);
3049 totalrank++;
3050 }
3051 }
3052 }
3053
3054 reg178_center = choose_reg178(info, timings);
3055
3056 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3057 info->training.timing_bounds[0][channel][slot][rank][lane].
3058 smallest =
3059 timings[info->training.
3060 reg178_smallest][channel][slot][rank][lane].
3061 smallest;
3062 info->training.timing_bounds[0][channel][slot][rank][lane].
3063 largest =
3064 timings[info->training.
3065 reg178_smallest][channel][slot][rank][lane].largest;
3066 info->training.timing_bounds[1][channel][slot][rank][lane].
3067 smallest =
3068 timings[info->training.
3069 reg178_largest][channel][slot][rank][lane].smallest;
3070 info->training.timing_bounds[1][channel][slot][rank][lane].
3071 largest =
3072 timings[info->training.
3073 reg178_largest][channel][slot][rank][lane].largest;
3074 info->training.timing_offset[channel][slot][rank][lane] =
3075 info->training.lane_timings[1][channel][slot][rank][lane]
3076 -
3077 info->training.lane_timings[0][channel][slot][rank][lane] +
3078 64;
3079 }
3080
3081 if (info->silicon_revision == 1
3082 && (info->
3083 populated_ranks_mask[1] ^ (info->
3084 populated_ranks_mask[1] >> 2)) & 1) {
3085 int ranks_after_channel1;
3086
3087 totalrank = 0;
3088 for (reg_178 = reg178_center - 18;
3089 reg_178 <= reg178_center + 18; reg_178 += 18) {
3090 totalrank = 0;
3091 set_178(reg_178);
3092 for (slot = 0; slot < NUM_SLOTS; slot++)
3093 for (rank = 0; rank < NUM_RANKS; rank++) {
3094 if (info->
3095 populated_ranks[1][slot][rank]) {
3096 train_ram_at_178(info, 1, slot,
3097 rank,
3098 totalrank,
3099 reg_178, 0,
3100 niter,
3101 timings);
3102 totalrank++;
3103 }
3104 }
3105 }
3106 ranks_after_channel1 = totalrank;
3107
3108 for (reg_178 = reg178_center - 12;
3109 reg_178 <= reg178_center + 12; reg_178 += 12) {
3110 totalrank = ranks_after_channel1;
3111 set_178(reg_178);
3112 for (slot = 0; slot < NUM_SLOTS; slot++)
3113 for (rank = 0; rank < NUM_RANKS; rank++)
3114 if (info->
3115 populated_ranks[0][slot][rank]) {
3116 train_ram_at_178(info, 0, slot,
3117 rank,
3118 totalrank,
3119 reg_178, 0,
3120 niter,
3121 timings);
3122 totalrank++;
3123 }
3124
3125 }
3126 } else {
3127 for (reg_178 = reg178_center - 12;
3128 reg_178 <= reg178_center + 12; reg_178 += 12) {
3129 totalrank = 0;
3130 set_178(reg_178);
3131 FOR_POPULATED_RANKS_BACKWARDS {
3132 train_ram_at_178(info, channel, slot, rank,
3133 totalrank, reg_178, 0, niter,
3134 timings);
3135 totalrank++;
3136 }
3137 }
3138 }
3139
3140 set_178(reg178_center);
3141 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3142 u16 tm0;
3143
3144 tm0 =
3145 choose_training(info, channel, slot, rank, lane, timings,
3146 reg178_center);
3147 write_500(info, channel, tm0,
3148 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3149 write_500(info, channel,
3150 tm0 +
3151 info->training.
3152 lane_timings[1][channel][slot][rank][lane] -
3153 info->training.
3154 lane_timings[0][channel][slot][rank][lane],
3155 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3156 }
3157
3158 totalrank = 0;
3159 FOR_POPULATED_RANKS_BACKWARDS {
3160 try_timing_offsets(info, channel, slot, rank, totalrank);
3161 totalrank++;
3162 }
Felix Held04be2dd2018-07-29 04:53:22 +02003163 MCHBAR8(0x243) = saved_243[0];
3164 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003165 write_1d0(0, 0x142, 3, 1);
3166 info->training.reg178_center = reg178_center;
3167}
3168
3169static void ram_training(struct raminfo *info)
3170{
3171 u16 saved_fc4;
3172
Felix Held04be2dd2018-07-29 04:53:22 +02003173 saved_fc4 = MCHBAR16(0xfc4);
3174 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003175
3176 if (info->revision >= 8)
3177 read_4090(info);
3178
3179 if (!try_cached_training(info))
3180 do_ram_training(info);
3181 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3182 && info->clock_speed_index < 2)
3183 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003184 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003185}
3186
Martin Roth468d02c2019-10-23 21:44:42 -06003187static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003188{
Martin Roth468d02c2019-10-23 21:44:42 -06003189 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003190 if (a > b) {
3191 t = a;
3192 a = b;
3193 b = t;
3194 }
3195 /* invariant a < b. */
3196 while (a) {
3197 t = b % a;
3198 b = a;
3199 a = t;
3200 }
3201 return b;
3202}
3203
3204static inline int div_roundup(int a, int b)
3205{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003206 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003207}
3208
Martin Roth468d02c2019-10-23 21:44:42 -06003209static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003210{
3211 return (a * b) / gcd(a, b);
3212}
3213
3214struct stru1 {
3215 u8 freqs_reversed;
3216 u8 freq_diff_reduced;
3217 u8 freq_min_reduced;
3218 u8 divisor_f4_to_fmax;
3219 u8 divisor_f3_to_fmax;
3220 u8 freq4_to_max_remainder;
3221 u8 freq3_to_2_remainder;
3222 u8 freq3_to_2_remaindera;
3223 u8 freq4_to_2_remainder;
3224 int divisor_f3_to_f1, divisor_f4_to_f2;
3225 int common_time_unit_ps;
3226 int freq_max_reduced;
3227};
3228
3229static void
3230compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3231 int num_cycles_2, int num_cycles_1, int round_it,
3232 int add_freqs, struct stru1 *result)
3233{
3234 int g;
3235 int common_time_unit_ps;
3236 int freq1_reduced, freq2_reduced;
3237 int freq_min_reduced;
3238 int freq_max_reduced;
3239 int freq3, freq4;
3240
3241 g = gcd(freq1, freq2);
3242 freq1_reduced = freq1 / g;
3243 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003244 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3245 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003246
3247 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3248 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3249 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3250 if (add_freqs) {
3251 freq3 += freq2_reduced;
3252 freq4 += freq1_reduced;
3253 }
3254
3255 if (round_it) {
3256 result->freq3_to_2_remainder = 0;
3257 result->freq3_to_2_remaindera = 0;
3258 result->freq4_to_max_remainder = 0;
3259 result->divisor_f4_to_f2 = 0;
3260 result->divisor_f3_to_f1 = 0;
3261 } else {
3262 if (freq2_reduced < freq1_reduced) {
3263 result->freq3_to_2_remainder =
3264 result->freq3_to_2_remaindera =
3265 freq3 % freq1_reduced - freq1_reduced + 1;
3266 result->freq4_to_max_remainder =
3267 -(freq4 % freq1_reduced);
3268 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3269 result->divisor_f4_to_f2 =
3270 (freq4 -
3271 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3272 result->freq4_to_2_remainder =
3273 -(char)((freq1_reduced - freq2_reduced) +
3274 ((u8) freq4 -
3275 (freq1_reduced -
3276 freq2_reduced)) % (u8) freq2_reduced);
3277 } else {
3278 if (freq2_reduced > freq1_reduced) {
3279 result->freq4_to_max_remainder =
3280 (freq4 % freq2_reduced) - freq2_reduced + 1;
3281 result->freq4_to_2_remainder =
3282 freq4 % freq_max_reduced -
3283 freq_max_reduced + 1;
3284 } else {
3285 result->freq4_to_max_remainder =
3286 -(freq4 % freq2_reduced);
3287 result->freq4_to_2_remainder =
3288 -(char)(freq4 % freq_max_reduced);
3289 }
3290 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3291 result->divisor_f3_to_f1 =
3292 (freq3 -
3293 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3294 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3295 result->freq3_to_2_remaindera =
3296 -(char)((freq_max_reduced - freq_min_reduced) +
3297 (freq3 -
3298 (freq_max_reduced -
3299 freq_min_reduced)) % freq1_reduced);
3300 }
3301 }
3302 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3303 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3304 if (round_it) {
3305 if (freq2_reduced > freq1_reduced) {
3306 if (freq3 % freq_max_reduced)
3307 result->divisor_f3_to_fmax++;
3308 }
3309 if (freq2_reduced < freq1_reduced) {
3310 if (freq4 % freq_max_reduced)
3311 result->divisor_f4_to_fmax++;
3312 }
3313 }
3314 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3315 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3316 result->freq_min_reduced = freq_min_reduced;
3317 result->common_time_unit_ps = common_time_unit_ps;
3318 result->freq_max_reduced = freq_max_reduced;
3319}
3320
3321static void
3322set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3323 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3324 int num_cycles_4, int reverse)
3325{
3326 struct stru1 vv;
3327 char multiplier;
3328
3329 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3330 0, 1, &vv);
3331
3332 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003333 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003334 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3335 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3336 div_roundup(num_cycles_1,
3337 vv.common_time_unit_ps) +
3338 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3339 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3340
3341 u32 y =
3342 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3343 vv.freq_max_reduced * multiplier)
3344 | (vv.
3345 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3346 multiplier) << 16) | ((u8) (vv.
3347 freq_min_reduced
3348 *
3349 multiplier)
3350 << 24);
3351 u32 x =
3352 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3353 divisor_f3_to_f1
3354 << 16)
3355 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3356 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003357 MCHBAR32(reg) = y;
3358 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003359 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003360 MCHBAR32(reg + 4) = y;
3361 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003362 }
3363}
3364
3365static void
3366set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3367 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3368 int num_cycles_4)
3369{
3370 struct stru1 ratios1;
3371 struct stru1 ratios2;
3372
3373 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3374 0, 1, &ratios2);
3375 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3376 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003377 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003378 ratios1.freq4_to_max_remainder | (ratios2.
3379 freq4_to_max_remainder
3380 << 8)
3381 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3382 divisor_f4_to_fmax
3383 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003384 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3385 (ratios2.freq4_to_max_remainder << 8) |
3386 (ratios1.divisor_f4_to_fmax << 16) |
3387 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003388}
3389
3390static void
3391set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3392 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3393{
3394 struct stru1 ratios;
3395
3396 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3397 round_it, add_freqs, &ratios);
3398 switch (mode) {
3399 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003400 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3401 (ratios.freqs_reversed << 8);
3402 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3403 (ratios.freq4_to_max_remainder << 8) |
3404 (ratios.divisor_f3_to_fmax << 16) |
3405 (ratios.divisor_f4_to_fmax << 20) |
3406 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003407 break;
3408
3409 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003410 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3411 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003412 break;
3413
3414 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003415 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3416 (ratios.freq4_to_max_remainder << 8) |
3417 (ratios.divisor_f3_to_fmax << 16) |
3418 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003419 break;
3420
3421 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003422 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3423 (ratios.divisor_f4_to_fmax << 8) |
3424 (ratios.freqs_reversed << 12) |
3425 (ratios.freq_min_reduced << 16) |
3426 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003427 break;
3428 }
3429}
3430
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003431static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003432{
3433 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3434 0, 1);
3435 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3436 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3437 1);
3438 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3439 frequency_11(info), 1231, 1524, 0, 1);
3440 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3441 frequency_11(info) / 2, 1278, 2008, 0, 1);
3442 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3443 1167, 1539, 0, 1);
3444 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3445 frequency_11(info) / 2, 1403, 1318, 0, 1);
3446 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3447 1);
3448 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3449 1);
3450 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3451 1, 1);
3452 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3453 1);
3454 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3455 frequency_11(info) / 2, 4000, 0, 0, 0);
3456 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3457 frequency_11(info) / 2, 4000, 4000, 0, 0);
3458
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003459 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003460 printk(RAM_SPEW, "[6dc] <= %x\n",
3461 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003462 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003463 } else
3464 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3465 info->delay46_ps[0], 0,
3466 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003467 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3468 frequency_11(info), 2500, 0, 0, 0);
3469 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3470 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003471 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003472 printk(RAM_SPEW, "[6e8] <= %x\n",
3473 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003474 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003475 } else
3476 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3477 info->delay46_ps[1], 0,
3478 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003479 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3480 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3481 470, 0);
3482 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3483 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3484 454, 459, 0);
3485 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3486 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3487 2588, 0);
3488 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3489 2405, 0);
3490 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3491 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3492 480, 0);
3493 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003494 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3495 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003496}
3497
3498static u16 get_max_timing(struct raminfo *info, int channel)
3499{
3500 int slot, rank, lane;
3501 u16 ret = 0;
3502
Felix Held04be2dd2018-07-29 04:53:22 +02003503 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 return 384;
3505
3506 if (info->revision < 8)
3507 return 256;
3508
3509 for (slot = 0; slot < NUM_SLOTS; slot++)
3510 for (rank = 0; rank < NUM_RANKS; rank++)
3511 if (info->populated_ranks[channel][slot][rank])
3512 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003513 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514 get_timing_register_addr
3515 (lane, 0, slot,
3516 rank), 9));
3517 return ret;
3518}
3519
3520static void set_274265(struct raminfo *info)
3521{
3522 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3523 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3524 int delay_e_over_cycle_ps;
3525 int cycletime_ps;
3526 int channel;
3527
3528 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003529 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003530 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3531 cycletime_ps =
3532 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3533 delay_d_ps =
3534 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3535 - info->some_delay_3_ps_rounded + 200;
3536 if (!
3537 ((info->silicon_revision == 0
3538 || info->silicon_revision == 1)
3539 && (info->revision >= 8)))
3540 delay_d_ps += halfcycle_ps(info) * 2;
3541 delay_d_ps +=
3542 halfcycle_ps(info) * (!info->revision_flag_1 +
3543 info->some_delay_2_halfcycles_ceil +
3544 2 * info->some_delay_1_cycle_floor +
3545 info->clock_speed_index +
3546 2 * info->cas_latency - 7 + 11);
3547 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3548
Felix Held04be2dd2018-07-29 04:53:22 +02003549 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3550 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3551 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003552 delay_d_ps += 650;
3553 delay_c_ps = delay_d_ps + 1800;
3554 if (delay_c_ps <= delay_a_ps)
3555 delay_e_ps = 0;
3556 else
3557 delay_e_ps =
3558 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3559 cycletime_ps);
3560
3561 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3562 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3563 delay_f_cycles =
3564 div_roundup(2500 - delay_e_over_cycle_ps,
3565 2 * halfcycle_ps(info));
3566 if (delay_f_cycles > delay_e_cycles) {
3567 info->delay46_ps[channel] = delay_e_ps;
3568 delay_e_cycles = 0;
3569 } else {
3570 info->delay46_ps[channel] =
3571 delay_e_over_cycle_ps +
3572 2 * halfcycle_ps(info) * delay_f_cycles;
3573 delay_e_cycles -= delay_f_cycles;
3574 }
3575
3576 if (info->delay46_ps[channel] < 2500) {
3577 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003578 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 }
3580 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3581 if (delay_b_ps <= delay_a_ps)
3582 delay_b_ps = 0;
3583 else
3584 delay_b_ps -= delay_a_ps;
3585 info->delay54_ps[channel] =
3586 cycletime_ps * div_roundup(delay_b_ps,
3587 cycletime_ps) -
3588 2 * halfcycle_ps(info) * delay_e_cycles;
3589 if (info->delay54_ps[channel] < 2500)
3590 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003591 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003592 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3593 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003594 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003596 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003597 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3598 4 * halfcycle_ps(info)) - 6;
3599 MCHBAR32((channel << 10) + 0x274) =
3600 info->training.reg274265[channel][1] |
3601 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003602 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003603 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3604 4 * halfcycle_ps(info)) + 1;
3605 MCHBAR16((channel << 10) + 0x265) =
3606 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003607 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003608 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003609 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610 else
Felix Held04be2dd2018-07-29 04:53:22 +02003611 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612}
3613
3614static void restore_274265(struct raminfo *info)
3615{
3616 int channel;
3617
3618 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003619 MCHBAR32((channel << 10) + 0x274) =
3620 (info->cached_training->reg274265[channel][0] << 16) |
3621 info->cached_training->reg274265[channel][1];
3622 MCHBAR16((channel << 10) + 0x265) =
3623 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003625 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003626 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627 else
Felix Held04be2dd2018-07-29 04:53:22 +02003628 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629}
3630
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631static void dmi_setup(void)
3632{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003633 gav(read8(DEFAULT_DMIBAR + 0x254));
3634 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3635 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003636 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003638 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639
3640 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3641 DEFAULT_GPIOBASE | 0x38);
3642 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3643}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003645void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003646{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003648 u16 ggc;
3649 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
Felix Held04be2dd2018-07-29 04:53:22 +02003651 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3653 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003654 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003655 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
3658 dmi_setup();
3659
Felix Held04be2dd2018-07-29 04:53:22 +02003660 MCHBAR16(0x1170) = 0xa880;
3661 MCHBAR8(0x11c1) = 0x1;
3662 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003663 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003665 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3666 /* 0 for 32MB */
3667 gfxsize = 0;
3668 }
3669
3670 ggc = 0xb00 | ((gfxsize + 5) << 4);
3671
Angel Pons16fe1e02020-07-22 16:12:33 +02003672 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673
3674 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003675 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676
3677 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003678 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003679 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003680 MCHBAR16_OR(0x2c30, 0x200);
3681 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003682 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003683 pci_read_config8(GMA, 0x62); // = 0x2
3684 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003685 read8(DEFAULT_RCBA + 0x2318);
3686 write8(DEFAULT_RCBA + 0x2318, 0x47);
3687 read8(DEFAULT_RCBA + 0x2320);
3688 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689 }
3690
Felix Heldf83d80b2018-07-29 05:30:30 +02003691 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003692
Angel Pons16fe1e02020-07-22 16:12:33 +02003693 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003694 gav(read32(DEFAULT_RCBA + 0x3428));
3695 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003696}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003697
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003698void raminit(const int s3resume, const u8 *spd_addrmap)
3699{
Martin Roth468d02c2019-10-23 21:44:42 -06003700 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003701 int i;
3702 struct raminfo info;
3703 u8 x2ca8;
3704 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003705 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003706
Felix Held04be2dd2018-07-29 04:53:22 +02003707 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003708
3709 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3710
Angel Pons16fe1e02020-07-22 16:12:33 +02003711 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712
3713 memset(&info, 0x5a, sizeof(info));
3714
3715 info.last_500_command[0] = 0;
3716 info.last_500_command[1] = 0;
3717
3718 info.fsb_frequency = 135 * 2;
3719 info.board_lane_delay[0] = 0x14;
3720 info.board_lane_delay[1] = 0x07;
3721 info.board_lane_delay[2] = 0x07;
3722 info.board_lane_delay[3] = 0x08;
3723 info.board_lane_delay[4] = 0x56;
3724 info.board_lane_delay[5] = 0x04;
3725 info.board_lane_delay[6] = 0x04;
3726 info.board_lane_delay[7] = 0x05;
3727 info.board_lane_delay[8] = 0x10;
3728
3729 info.training.reg_178 = 0;
3730 info.training.reg_10b = 0;
3731
3732 info.heci_bar = 0;
3733 info.memory_reserved_for_heci_mb = 0;
3734
3735 /* before SPD */
3736 timestamp_add_now(101);
3737
Felix Held29a9c072018-07-29 01:34:45 +02003738 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003739 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003740
3741 collect_system_info(&info);
3742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003743 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3744
3745 info.use_ecc = 1;
3746 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003747 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003748 int v;
3749 int try;
3750 int addr;
3751 const u8 useful_addresses[] = {
3752 DEVICE_TYPE,
3753 MODULE_TYPE,
3754 DENSITY,
3755 RANKS_AND_DQ,
3756 MEMORY_BUS_WIDTH,
3757 TIMEBASE_DIVIDEND,
3758 TIMEBASE_DIVISOR,
3759 CYCLETIME,
3760 CAS_LATENCIES_LSB,
3761 CAS_LATENCIES_MSB,
3762 CAS_LATENCY_TIME,
3763 0x11, 0x12, 0x13, 0x14, 0x15,
3764 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3765 0x1c, 0x1d,
3766 THERMAL_AND_REFRESH,
3767 0x20,
3768 REFERENCE_RAW_CARD_USED,
3769 RANK1_ADDRESS_MAPPING,
3770 0x75, 0x76, 0x77, 0x78,
3771 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3772 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3773 0x85, 0x86, 0x87, 0x88,
3774 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3775 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3776 0x95
3777 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003778 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779 continue;
3780 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003781 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003782 DEVICE_TYPE);
3783 if (v >= 0)
3784 break;
3785 }
3786 if (v < 0)
3787 continue;
3788 for (addr = 0;
3789 addr <
3790 sizeof(useful_addresses) /
3791 sizeof(useful_addresses[0]); addr++)
3792 gav(info.
3793 spd[channel][0][useful_addresses
3794 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003795 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003796 useful_addresses
3797 [addr]));
3798 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3799 die("Only DDR3 is supported");
3800
3801 v = info.spd[channel][0][RANKS_AND_DQ];
3802 info.populated_ranks[channel][0][0] = 1;
3803 info.populated_ranks[channel][0][1] =
3804 ((v >> 3) & 7);
3805 if (((v >> 3) & 7) > 1)
3806 die("At most 2 ranks are supported");
3807 if ((v & 7) == 0 || (v & 7) > 2)
3808 die("Only x8 and x16 modules are supported");
3809 if ((info.
3810 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3811 && (info.
3812 spd[channel][slot][MODULE_TYPE] & 0xF)
3813 != 3)
3814 die("Registered memory is not supported");
3815 info.is_x16_module[channel][0] = (v & 7) - 1;
3816 info.density[channel][slot] =
3817 info.spd[channel][slot][DENSITY] & 0xF;
3818 if (!
3819 (info.
3820 spd[channel][slot][MEMORY_BUS_WIDTH] &
3821 0x18))
3822 info.use_ecc = 0;
3823 }
3824
3825 gav(0x55);
3826
3827 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3828 int v = 0;
3829 for (slot = 0; slot < NUM_SLOTS; slot++)
3830 for (rank = 0; rank < NUM_RANKS; rank++)
3831 v |= info.
3832 populated_ranks[channel][slot][rank]
3833 << (2 * slot + rank);
3834 info.populated_ranks_mask[channel] = v;
3835 }
3836
3837 gav(0x55);
3838
Angel Pons16fe1e02020-07-22 16:12:33 +02003839 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840 }
3841
3842 /* after SPD */
3843 timestamp_add_now(102);
3844
Felix Held04be2dd2018-07-29 04:53:22 +02003845 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003846
3847 collect_system_info(&info);
3848 calculate_timings(&info);
3849
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003851 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003852 if (x2ca8 == 0 && (reg8 & 0x80)) {
3853 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3854 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3855 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3856 */
3857
3858 /* Clear bit7. */
3859
3860 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3861 (reg8 & ~(1 << 7)));
3862
3863 printk(BIOS_INFO,
3864 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003865 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866 }
3867 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868
3869 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003870 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3871 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872
3873 compute_derived_timings(&info);
3874
3875 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003876 gav(MCHBAR8(0x164));
3877 MCHBAR8(0x164) = 0x26;
3878 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879 }
3880
Felix Held04be2dd2018-07-29 04:53:22 +02003881 MCHBAR32_OR(0x18b4, 0x210000);
3882 MCHBAR32_OR(0x1890, 0x2000000);
3883 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003885 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3886 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887
Felix Held04be2dd2018-07-29 04:53:22 +02003888 gav(MCHBAR16(0x2c10));
3889 MCHBAR16(0x2c10) = 0x412;
3890 gav(MCHBAR16(0x2c10));
3891 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
Felix Held04be2dd2018-07-29 04:53:22 +02003893 gav(MCHBAR8(0x2ca8)); // !!!!
3894 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003896 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3897 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003898 gav(MCHBAR32(0x1c04)); // !!!!
3899 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900
3901 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003902 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003903 }
3904
Felix Held04be2dd2018-07-29 04:53:22 +02003905 MCHBAR32(0x18d8) = 0x120000;
3906 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003907 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3908 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003909 MCHBAR32(0x18d8) = 0x40000;
3910 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003911 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3912 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003913 MCHBAR32(0x18d8) = 0x180000;
3914 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003915 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3916 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003917 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003918
Felix Held04be2dd2018-07-29 04:53:22 +02003919 gav(MCHBAR32(0x18dc)); // !!!!
3920 MCHBAR32(0x18dc) = 0x3;
3921 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922
3923 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925 }
3926
Felix Held04be2dd2018-07-29 04:53:22 +02003927 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003928 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003929 MCHBAR32(0x1a10) = 0x4200010e;
3930 MCHBAR32_OR(0x18b8, 0x200);
3931 gav(MCHBAR32(0x1918)); // !!!!
3932 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003933
Felix Held04be2dd2018-07-29 04:53:22 +02003934 gav(MCHBAR32(0x18b8)); // !!!!
3935 MCHBAR32(0x18b8) = 0xe00;
3936 gav(MCHBAR32(0x182c)); // !!!!
3937 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003938 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003940 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3941 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003942
Felix Held04be2dd2018-07-29 04:53:22 +02003943 MCHBAR32_AND(0x18b4, 0xffff7fff);
3944 gav(MCHBAR32(0x1a68)); // !!!!
3945 MCHBAR32(0x1a68) = 0x343800;
3946 gav(MCHBAR32(0x1e68)); // !!!!
3947 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948
3949 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003950 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003951 }
3952
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003953 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3954 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3955 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3956 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3957 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3958 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3959 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003960 gav(MCHBAR32(0x1af0)); // !!!!
3961 gav(MCHBAR32(0x1af0)); // !!!!
3962 MCHBAR32(0x1af0) = 0x1f020003;
3963 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003964
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003965 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003966 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967 }
3968
Felix Held04be2dd2018-07-29 04:53:22 +02003969 gav(MCHBAR32(0x1890)); // !!!!
3970 MCHBAR32(0x1890) = 0x80102;
3971 gav(MCHBAR32(0x18b4)); // !!!!
3972 MCHBAR32(0x18b4) = 0x216000;
3973 MCHBAR32(0x18a4) = 0x22222222;
3974 MCHBAR32(0x18a8) = 0x22222222;
3975 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976
3977 udelay(1000);
3978
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003979 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003980
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003981 if (x2ca8 == 0) {
3982 int j;
3983 if (s3resume && info.cached_training) {
3984 restore_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.cached_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.cached_training->reg274265[i][j]);
3991 } else {
3992 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003993 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003994 info.training.reg2ca9_bit0);
3995 for (i = 0; i < 2; i++)
3996 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003997 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003998 i, j, info.training.reg274265[i][j]);
3999 }
4000
4001 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004002
4003 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004004 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004005 }
4006
4007 udelay(1000);
4008
4009 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004010 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004011 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004012 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4013 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4014 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004015
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004016 MCHBAR8(0x1150);
4017 MCHBAR8(0x1151);
4018 MCHBAR8(0x1022);
4019 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004020 MCHBAR32(0x1300) = 0x60606060;
4021 MCHBAR32(0x1304) = 0x60606060;
4022 MCHBAR32(0x1308) = 0x78797a7b;
4023 MCHBAR32(0x130c) = 0x7c7d7e7f;
4024 MCHBAR32(0x1310) = 0x60606060;
4025 MCHBAR32(0x1314) = 0x60606060;
4026 MCHBAR32(0x1318) = 0x60606060;
4027 MCHBAR32(0x131c) = 0x60606060;
4028 MCHBAR32(0x1320) = 0x50515253;
4029 MCHBAR32(0x1324) = 0x54555657;
4030 MCHBAR32(0x1328) = 0x58595a5b;
4031 MCHBAR32(0x132c) = 0x5c5d5e5f;
4032 MCHBAR32(0x1330) = 0x40414243;
4033 MCHBAR32(0x1334) = 0x44454647;
4034 MCHBAR32(0x1338) = 0x48494a4b;
4035 MCHBAR32(0x133c) = 0x4c4d4e4f;
4036 MCHBAR32(0x1340) = 0x30313233;
4037 MCHBAR32(0x1344) = 0x34353637;
4038 MCHBAR32(0x1348) = 0x38393a3b;
4039 MCHBAR32(0x134c) = 0x3c3d3e3f;
4040 MCHBAR32(0x1350) = 0x20212223;
4041 MCHBAR32(0x1354) = 0x24252627;
4042 MCHBAR32(0x1358) = 0x28292a2b;
4043 MCHBAR32(0x135c) = 0x2c2d2e2f;
4044 MCHBAR32(0x1360) = 0x10111213;
4045 MCHBAR32(0x1364) = 0x14151617;
4046 MCHBAR32(0x1368) = 0x18191a1b;
4047 MCHBAR32(0x136c) = 0x1c1d1e1f;
4048 MCHBAR32(0x1370) = 0x10203;
4049 MCHBAR32(0x1374) = 0x4050607;
4050 MCHBAR32(0x1378) = 0x8090a0b;
4051 MCHBAR32(0x137c) = 0xc0d0e0f;
4052 MCHBAR8(0x11cc) = 0x4e;
4053 MCHBAR32(0x1110) = 0x73970404;
4054 MCHBAR32(0x1114) = 0x72960404;
4055 MCHBAR32(0x1118) = 0x6f950404;
4056 MCHBAR32(0x111c) = 0x6d940404;
4057 MCHBAR32(0x1120) = 0x6a930404;
4058 MCHBAR32(0x1124) = 0x68a41404;
4059 MCHBAR32(0x1128) = 0x66a21404;
4060 MCHBAR32(0x112c) = 0x63a01404;
4061 MCHBAR32(0x1130) = 0x609e1404;
4062 MCHBAR32(0x1134) = 0x5f9c1404;
4063 MCHBAR32(0x1138) = 0x5c961404;
4064 MCHBAR32(0x113c) = 0x58a02404;
4065 MCHBAR32(0x1140) = 0x54942404;
4066 MCHBAR32(0x1190) = 0x900080a;
4067 MCHBAR16(0x11c0) = 0xc40b;
4068 MCHBAR16(0x11c2) = 0x303;
4069 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004070 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004071 MCHBAR32(0x11b8) = 0x70c3000;
4072 MCHBAR8(0x11ec) = 0xa;
4073 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004074 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004075 MCHBAR16(0x11ca) = 0xfa;
4076 MCHBAR32(0x11e4) = 0x4e20;
4077 MCHBAR8(0x11bc) = 0xf;
4078 MCHBAR16(0x11da) = 0x19;
4079 MCHBAR16(0x11ba) = 0x470c;
4080 MCHBAR32(0x1680) = 0xe6ffe4ff;
4081 MCHBAR32(0x1684) = 0xdeffdaff;
4082 MCHBAR32(0x1688) = 0xd4ffd0ff;
4083 MCHBAR32(0x168c) = 0xccffc6ff;
4084 MCHBAR32(0x1690) = 0xc0ffbeff;
4085 MCHBAR32(0x1694) = 0xb8ffb0ff;
4086 MCHBAR32(0x1698) = 0xa8ff0000;
4087 MCHBAR32(0x169c) = 0xc00;
4088 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004089 }
4090
Felix Held04be2dd2018-07-29 04:53:22 +02004091 MCHBAR32(0x124c) = 0x15040d00;
4092 MCHBAR32(0x1250) = 0x7f0000;
4093 MCHBAR32(0x1254) = 0x1e220004;
4094 MCHBAR32(0x1258) = 0x4000004;
4095 MCHBAR32(0x1278) = 0x0;
4096 MCHBAR32(0x125c) = 0x0;
4097 MCHBAR32(0x1260) = 0x0;
4098 MCHBAR32(0x1264) = 0x0;
4099 MCHBAR32(0x1268) = 0x0;
4100 MCHBAR32(0x126c) = 0x0;
4101 MCHBAR32(0x1270) = 0x0;
4102 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004103 }
4104
4105 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004106 MCHBAR16(0x1214) = 0x320;
4107 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004108 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4109 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004110 MCHBAR32(0x1400) = 0x13040020;
4111 MCHBAR32(0x1404) = 0xe090120;
4112 MCHBAR32(0x1408) = 0x5120220;
4113 MCHBAR32(0x140c) = 0x5120330;
4114 MCHBAR32(0x1410) = 0xe090220;
4115 MCHBAR32(0x1414) = 0x1010001;
4116 MCHBAR32(0x1418) = 0x1110000;
4117 MCHBAR32(0x141c) = 0x9020020;
4118 MCHBAR32(0x1420) = 0xd090220;
4119 MCHBAR32(0x1424) = 0x2090220;
4120 MCHBAR32(0x1428) = 0x2090330;
4121 MCHBAR32(0x142c) = 0xd090220;
4122 MCHBAR32(0x1430) = 0x1010001;
4123 MCHBAR32(0x1434) = 0x1110000;
4124 MCHBAR32(0x1438) = 0x11040020;
4125 MCHBAR32(0x143c) = 0x4030220;
4126 MCHBAR32(0x1440) = 0x1060220;
4127 MCHBAR32(0x1444) = 0x1060330;
4128 MCHBAR32(0x1448) = 0x4030220;
4129 MCHBAR32(0x144c) = 0x1010001;
4130 MCHBAR32(0x1450) = 0x1110000;
4131 MCHBAR32(0x1454) = 0x4010020;
4132 MCHBAR32(0x1458) = 0xb090220;
4133 MCHBAR32(0x145c) = 0x1090220;
4134 MCHBAR32(0x1460) = 0x1090330;
4135 MCHBAR32(0x1464) = 0xb090220;
4136 MCHBAR32(0x1468) = 0x1010001;
4137 MCHBAR32(0x146c) = 0x1110000;
4138 MCHBAR32(0x1470) = 0xf040020;
4139 MCHBAR32(0x1474) = 0xa090220;
4140 MCHBAR32(0x1478) = 0x1120220;
4141 MCHBAR32(0x147c) = 0x1120330;
4142 MCHBAR32(0x1480) = 0xa090220;
4143 MCHBAR32(0x1484) = 0x1010001;
4144 MCHBAR32(0x1488) = 0x1110000;
4145 MCHBAR32(0x148c) = 0x7020020;
4146 MCHBAR32(0x1490) = 0x1010220;
4147 MCHBAR32(0x1494) = 0x10210;
4148 MCHBAR32(0x1498) = 0x10320;
4149 MCHBAR32(0x149c) = 0x1010220;
4150 MCHBAR32(0x14a0) = 0x1010001;
4151 MCHBAR32(0x14a4) = 0x1110000;
4152 MCHBAR32(0x14a8) = 0xd040020;
4153 MCHBAR32(0x14ac) = 0x8090220;
4154 MCHBAR32(0x14b0) = 0x1111310;
4155 MCHBAR32(0x14b4) = 0x1111420;
4156 MCHBAR32(0x14b8) = 0x8090220;
4157 MCHBAR32(0x14bc) = 0x1010001;
4158 MCHBAR32(0x14c0) = 0x1110000;
4159 MCHBAR32(0x14c4) = 0x3010020;
4160 MCHBAR32(0x14c8) = 0x7090220;
4161 MCHBAR32(0x14cc) = 0x1081310;
4162 MCHBAR32(0x14d0) = 0x1081420;
4163 MCHBAR32(0x14d4) = 0x7090220;
4164 MCHBAR32(0x14d8) = 0x1010001;
4165 MCHBAR32(0x14dc) = 0x1110000;
4166 MCHBAR32(0x14e0) = 0xb040020;
4167 MCHBAR32(0x14e4) = 0x2030220;
4168 MCHBAR32(0x14e8) = 0x1051310;
4169 MCHBAR32(0x14ec) = 0x1051420;
4170 MCHBAR32(0x14f0) = 0x2030220;
4171 MCHBAR32(0x14f4) = 0x1010001;
4172 MCHBAR32(0x14f8) = 0x1110000;
4173 MCHBAR32(0x14fc) = 0x5020020;
4174 MCHBAR32(0x1500) = 0x5090220;
4175 MCHBAR32(0x1504) = 0x2071310;
4176 MCHBAR32(0x1508) = 0x2071420;
4177 MCHBAR32(0x150c) = 0x5090220;
4178 MCHBAR32(0x1510) = 0x1010001;
4179 MCHBAR32(0x1514) = 0x1110000;
4180 MCHBAR32(0x1518) = 0x7040120;
4181 MCHBAR32(0x151c) = 0x2090220;
4182 MCHBAR32(0x1520) = 0x70b1210;
4183 MCHBAR32(0x1524) = 0x70b1310;
4184 MCHBAR32(0x1528) = 0x2090220;
4185 MCHBAR32(0x152c) = 0x1010001;
4186 MCHBAR32(0x1530) = 0x1110000;
4187 MCHBAR32(0x1534) = 0x1010110;
4188 MCHBAR32(0x1538) = 0x1081310;
4189 MCHBAR32(0x153c) = 0x5041200;
4190 MCHBAR32(0x1540) = 0x5041310;
4191 MCHBAR32(0x1544) = 0x1081310;
4192 MCHBAR32(0x1548) = 0x1010001;
4193 MCHBAR32(0x154c) = 0x1110000;
4194 MCHBAR32(0x1550) = 0x1040120;
4195 MCHBAR32(0x1554) = 0x4051210;
4196 MCHBAR32(0x1558) = 0xd051200;
4197 MCHBAR32(0x155c) = 0xd051200;
4198 MCHBAR32(0x1560) = 0x4051210;
4199 MCHBAR32(0x1564) = 0x1010001;
4200 MCHBAR32(0x1568) = 0x1110000;
4201 MCHBAR16(0x1222) = 0x220a;
4202 MCHBAR16(0x123c) = 0x1fc0;
4203 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004204 }
4205
Felix Heldf83d80b2018-07-29 05:30:30 +02004206 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004207 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004208 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004209
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004210 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004211
4212 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004213 MCHBAR8_AND(0x2ca8, ~3);
4214 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004215 /* This issues a CPU reset without resetting the platform */
4216 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004217 /* Write back the S3 state to PM1_CNT to let the reset CPU
4218 know it also needs to take the s3 path. */
4219 if (s3resume)
4220 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4221 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004222 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004223 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004224 }
4225
Felix Held04be2dd2018-07-29 04:53:22 +02004226 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004227 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004228 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004229 MCHBAR16(0x2c20); // !!!!
4230 MCHBAR16(0x2c10); // !!!!
4231 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004232 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004233 udelay(1000);
4234 write_1d0(0, 0x33d, 0, 0);
4235 write_500(&info, 0, 0, 0xb61, 0, 0);
4236 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004237 MCHBAR32(0x1a30) = 0x0;
4238 MCHBAR32(0x1a34) = 0x0;
4239 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4240 (info.populated_ranks[0][0][0] * 0xa0);
4241 MCHBAR16(0x616) = 0x26a;
4242 MCHBAR32(0x134) = 0x856000;
4243 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004244 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4245 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004246 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004247 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4248 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004249 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004250 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004251 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4252 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4254 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4255 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4256 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4257 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4258 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4259 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4260 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4261 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4262 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004263 }
4264
4265 write_1d0(0x4, 0x151, 4, 1);
4266 write_1d0(0, 0x142, 3, 1);
4267 rdmsr(0x1ac); // !!!!
4268 write_500(&info, 1, 1, 0x6b3, 4, 1);
4269 write_500(&info, 1, 1, 0x6cf, 4, 1);
4270
4271 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4272
4273 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4274 populated_ranks[0]
4275 [0][0]) << 0),
4276 0x1d1, 3, 1);
4277 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004278 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4279 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004280 }
4281
4282 set_334(0);
4283
4284 program_base_timings(&info);
4285
Felix Held04be2dd2018-07-29 04:53:22 +02004286 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004287
4288 write_1d0(0x2, 0x1d5, 2, 1);
4289 write_1d0(0x20, 0x166, 7, 1);
4290 write_1d0(0x0, 0xeb, 3, 1);
4291 write_1d0(0x0, 0xf3, 6, 1);
4292
4293 for (channel = 0; channel < NUM_CHANNELS; channel++)
4294 for (lane = 0; lane < 9; lane++) {
4295 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4296 u8 a;
4297 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4298 write_500(&info, channel, a, addr, 6, 1);
4299 }
4300
4301 udelay(1000);
4302
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004303 if (s3resume) {
4304 if (info.cached_training == NULL) {
4305 u32 reg32;
4306 printk(BIOS_ERR,
4307 "Couldn't find training data. Rebooting\n");
4308 reg32 = inl(DEFAULT_PMBASE + 0x04);
4309 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004310 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004311 }
4312 int tm;
4313 info.training = *info.cached_training;
4314 for (tm = 0; tm < 4; tm++)
4315 for (channel = 0; channel < NUM_CHANNELS; channel++)
4316 for (slot = 0; slot < NUM_SLOTS; slot++)
4317 for (rank = 0; rank < NUM_RANKS; rank++)
4318 for (lane = 0; lane < 9; lane++)
4319 write_500(&info,
4320 channel,
4321 info.training.
4322 lane_timings
4323 [tm][channel]
4324 [slot][rank]
4325 [lane],
4326 get_timing_register_addr
4327 (lane, tm,
4328 slot, rank),
4329 9, 0);
4330 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4331 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4332 }
4333
Felix Heldf83d80b2018-07-29 05:30:30 +02004334 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004335 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004336 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004337 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004338
4339 program_board_delay(&info);
4340
Felix Held04be2dd2018-07-29 04:53:22 +02004341 MCHBAR8(0x5ff) = 0x0;
4342 MCHBAR8(0x5ff) = 0x80;
4343 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004344
Felix Held04be2dd2018-07-29 04:53:22 +02004345 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004346 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004347 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004348 gav(read_1d0(0x14b, 7)); // = 0x81023100
4349 write_1d0(0x30, 0x14b, 7, 1);
4350 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4351 write_1d0(7, 0xd6, 6, 1);
4352 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4353 write_1d0(7, 0x328, 6, 1);
4354
4355 for (channel = 0; channel < NUM_CHANNELS; channel++)
4356 set_4cf(&info, channel,
4357 info.populated_ranks[channel][0][0] ? 8 : 0);
4358
4359 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4360 write_1d0(2, 0x116, 4, 1);
4361 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4362 write_1d0(0, 0xae, 6, 1);
4363 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4364 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004365 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4366 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004367 MCHBAR32_AND(0x140, ~0x07000000);
4368 MCHBAR32_AND(0x138, ~0x07000000);
4369 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004370 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004371 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004372 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004373
4374 {
4375 u32 t;
4376 u8 val_a1;
4377 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4378 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4379 rmw_1d0(0x320, 0x07,
4380 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4381 rmw_1d0(0x14b, 0x78,
4382 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4383 4), 7,
4384 1);
4385 rmw_1d0(0xce, 0x38,
4386 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4387 4), 6,
4388 1);
4389 }
4390
4391 for (channel = 0; channel < NUM_CHANNELS; channel++)
4392 set_4cf(&info, channel,
4393 info.populated_ranks[channel][0][0] ? 9 : 1);
4394
4395 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004396 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004397 write_1d0(2, 0xae, 6, 1);
4398 write_1d0(2, 0x300, 6, 1);
4399 write_1d0(2, 0x121, 3, 1);
4400 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4401 write_1d0(4, 0xd6, 6, 1);
4402 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4403 write_1d0(4, 0x328, 6, 1);
4404
4405 for (channel = 0; channel < NUM_CHANNELS; channel++)
4406 set_4cf(&info, channel,
4407 info.populated_ranks[channel][0][0] ? 9 : 0);
4408
Felix Held04be2dd2018-07-29 04:53:22 +02004409 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4410 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004411 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004412 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004413 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4414 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4415 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4416 write_1d0(0, 0x21c, 6, 1);
4417 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4418 write_1d0(0x35, 0x14b, 7, 1);
4419
4420 for (channel = 0; channel < NUM_CHANNELS; channel++)
4421 set_4cf(&info, channel,
4422 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4423
4424 set_334(1);
4425
Felix Held04be2dd2018-07-29 04:53:22 +02004426 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004427
4428 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4429 write_500(&info, channel,
4430 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4431 1);
4432 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4433 }
Felix Held04be2dd2018-07-29 04:53:22 +02004434 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4435 MCHBAR16(0x6c0) = 0x14a0;
4436 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4437 MCHBAR16(0x232) = 0x8;
4438 /* 0x40004 or 0 depending on ? */
4439 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4440 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4441 MCHBAR32(0x128) = 0x2150d05;
4442 MCHBAR8(0x12c) = 0x1f;
4443 MCHBAR8(0x12d) = 0x56;
4444 MCHBAR8(0x12e) = 0x31;
4445 MCHBAR8(0x12f) = 0x0;
4446 MCHBAR8(0x271) = 0x2;
4447 MCHBAR8(0x671) = 0x2;
4448 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004449 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004450 MCHBAR32(0x294 + (channel << 10)) =
4451 (info.populated_ranks_mask[channel] & 3) << 16;
4452 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4453 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004454 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004455 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4456 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457
4458 if (!s3resume)
4459 jedec_init(&info);
4460
4461 int totalrank = 0;
4462 for (channel = 0; channel < NUM_CHANNELS; channel++)
4463 for (slot = 0; slot < NUM_SLOTS; slot++)
4464 for (rank = 0; rank < NUM_RANKS; rank++)
4465 if (info.populated_ranks[channel][slot][rank]) {
4466 jedec_read(&info, channel, slot, rank,
4467 totalrank, 0xa, 0x400);
4468 totalrank++;
4469 }
4470
Felix Held04be2dd2018-07-29 04:53:22 +02004471 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004472
Felix Heldf83d80b2018-07-29 05:30:30 +02004473 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4474 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475
4476 if (!s3resume) {
4477 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004478 MCHBAR32(0x294 + (channel << 10)) =
4479 (info.populated_ranks_mask[channel] & 3) << 16;
4480 MCHBAR16(0x298 + (channel << 10)) =
4481 info.populated_ranks[channel][0][0] |
4482 (info.populated_ranks[channel][0][1] << 5);
4483 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004485 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004486
4487 {
4488 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004489 a = MCHBAR8(0x243);
4490 b = MCHBAR8(0x643);
4491 MCHBAR8(0x243) = a | 2;
4492 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493 }
4494
4495 write_1d0(7, 0x19b, 3, 1);
4496 write_1d0(7, 0x1c0, 3, 1);
4497 write_1d0(4, 0x1c6, 4, 1);
4498 write_1d0(4, 0x1cc, 4, 1);
4499 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4500 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004501 MCHBAR32(0x584) = 0xfffff;
4502 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004503
4504 for (channel = 0; channel < NUM_CHANNELS; channel++)
4505 for (slot = 0; slot < NUM_SLOTS; slot++)
4506 for (rank = 0; rank < NUM_RANKS; rank++)
4507 if (info.
4508 populated_ranks[channel][slot]
4509 [rank])
4510 config_rank(&info, s3resume,
4511 channel, slot,
4512 rank);
4513
Felix Held04be2dd2018-07-29 04:53:22 +02004514 MCHBAR8(0x243) = 0x1;
4515 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004516 }
4517
4518 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004519 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 write_26c(0, 0x820);
4521 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004522 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523 /* end */
4524
4525 if (s3resume) {
4526 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004527 MCHBAR32(0x294 + (channel << 10)) =
4528 (info.populated_ranks_mask[channel] & 3) << 16;
4529 MCHBAR16(0x298 + (channel << 10)) =
4530 info.populated_ranks[channel][0][0] |
4531 (info.populated_ranks[channel][0][1] << 5);
4532 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004534 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535 }
4536
Felix Held04be2dd2018-07-29 04:53:22 +02004537 MCHBAR32_AND(0xfa4, ~0x01000002);
4538 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004539
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540 /* Before training. */
4541 timestamp_add_now(103);
4542
4543 if (!s3resume)
4544 ram_training(&info);
4545
4546 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004547 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004548
4549 dump_timings(&info);
4550
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004551 program_modules_memory_map(&info, 0);
4552 program_total_memory_map(&info);
4553
4554 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004555 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004557 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004559 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 else
Felix Held04be2dd2018-07-29 04:53:22 +02004561 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004562
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32_AND(0xfac, ~0x80000000);
4564 MCHBAR32(0xfb4) = 0x4800;
4565 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4566 MCHBAR32(0xe94) = 0x7ffff;
4567 MCHBAR32(0xfc0) = 0x80002040;
4568 MCHBAR32(0xfc4) = 0x701246;
4569 MCHBAR8_AND(0xfc8, ~0x70);
4570 MCHBAR32_OR(0xe5c, 0x1000000);
4571 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4572 MCHBAR32(0x50) = 0x700b0;
4573 MCHBAR32(0x3c) = 0x10;
4574 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4575 MCHBAR8_OR(0xff4, 0x2);
4576 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4579 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4580 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004582 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4583 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4584 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586 {
4587 u32 eax;
4588
4589 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4591 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4592 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 }
4594
4595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599 else
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004601
Felix Held04be2dd2018-07-29 04:53:22 +02004602 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004603
Felix Held04be2dd2018-07-29 04:53:22 +02004604 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004605 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004606 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004607 else
Felix Held04be2dd2018-07-29 04:53:22 +02004608 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004609 }
4610
Felix Held04be2dd2018-07-29 04:53:22 +02004611 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004612
4613 {
4614 u8 al;
4615 al = 0xd;
4616 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4617 al += 2;
4618 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004619 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004620 }
4621
4622 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004623 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4624 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4625 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4626 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627 }
4628 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004629 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004630 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004631 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004632 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004633 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004634 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR8_OR(0x1210, 2);
4636 MCHBAR32(0x1200) = 0x8800440;
4637 MCHBAR32(0x1204) = 0x53ff0453;
4638 MCHBAR32(0x1208) = 0x19002043;
4639 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004640
4641 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR16(0x1214) = 0x220;
4643 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644 }
4645
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR8_OR(0x1214, 0x4);
4647 MCHBAR8(0x120c) = 0x1;
4648 MCHBAR8(0x1218) = 0x3;
4649 MCHBAR8(0x121a) = 0x3;
4650 MCHBAR8(0x121c) = 0x3;
4651 MCHBAR16(0xc14) = 0x0;
4652 MCHBAR16(0xc20) = 0x0;
4653 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
4655 /* revision dependent here. */
4656
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658
4659 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR16_OR(0x1230, 0x8000);
4663 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004664
4665 u8 bl, ebpb;
4666 u16 reg_1020;
4667
Felix Held04be2dd2018-07-29 04:53:22 +02004668 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4669 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004670
Felix Held04be2dd2018-07-29 04:53:22 +02004671 MCHBAR32(0x1000) = 0x100;
4672 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
4674 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676 bl = reg_1020 >> 8;
4677 ebpb = reg_1020 & 0xff;
4678 } else {
4679 ebpb = 0;
4680 bl = 8;
4681 }
4682
4683 rdmsr(0x1a2);
4684
Felix Held04be2dd2018-07-29 04:53:22 +02004685 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004686
Felix Held04be2dd2018-07-29 04:53:22 +02004687 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688
Felix Held04be2dd2018-07-29 04:53:22 +02004689 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4694 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 }
4696
4697 setup_heci_uma(&info);
4698
4699 if (info.uma_enabled) {
4700 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004701 MCHBAR32_OR(0x11b0, 0x4000);
4702 MCHBAR32_OR(0x11b4, 0x4000);
4703 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
Felix Held04be2dd2018-07-29 04:53:22 +02004705 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4706 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4707 MCHBAR16_OR(0x1170, 0x1000);
4708
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004710
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004712 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004713 ;
4714 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004715 }
4716
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004717 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4718 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004720 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722 udelay(1000);
4723 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004724 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4725
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726 if (!s3resume)
4727 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004728 if (s3resume && cbmem_wasnot_inited) {
4729 u32 reg32;
4730 printk(BIOS_ERR, "Failed S3 resume.\n");
4731 ram_check(0x100000, 0x200000);
4732
4733 /* Clear SLP_TYPE. */
4734 reg32 = inl(DEFAULT_PMBASE + 0x04);
4735 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4736
4737 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004738 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004739 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004740}