blob: daa088651f761469d169671d126771ea85672c4e [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Angel Pons36592bf2020-09-14 18:52:44 +020064#define MRC_CACHE_VERSION 3
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Angel Ponsc2d6f5f2020-12-11 23:48:51 +0100104/*
105 * Ironlake memory I/O timings are located in scan chains, accessible
106 * through MCHBAR register groups. Each channel has a scan chain, and
107 * there's a global scan chain too. Each chain is broken into smaller
108 * sections of N bits, where N <= 32. Each section allows reading and
109 * writing a certain parameter. Each section contains N - 2 data bits
110 * and two additional bits: a Mask bit, and a Halt bit.
111 */
112
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100113/* OK */
114static void write_1d0(u32 val, u16 addr, int bits, int flag)
115{
Felix Held04be2dd2018-07-29 04:53:22 +0200116 MCHBAR32(0x1d0) = 0;
117 while (MCHBAR32(0x1d0) & 0x800000)
118 ;
119 MCHBAR32(0x1d4) =
120 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
121 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200122 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200123 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100124}
125
126/* OK */
127static u16 read_1d0(u16 addr, int split)
128{
129 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200130 MCHBAR32(0x1d0) = 0;
131 while (MCHBAR32(0x1d0) & 0x800000)
132 ;
133 MCHBAR32(0x1d0) =
134 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
135 while (MCHBAR32(0x1d0) & 0x800000)
136 ;
137 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100138 write_1d0(0, 0x33d, 0, 0);
139 write_1d0(0, 0x33d, 0, 0);
140 val &= ((1 << split) - 1);
141 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
142 return val;
143}
144
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800145static void write32p(uintptr_t addr, uint32_t val)
146{
147 write32((void *)addr, val);
148}
149
150static uint32_t read32p(uintptr_t addr)
151{
152 return read32((void *)addr);
153}
154
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100155static void sfence(void)
156{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100157 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100158}
159
160static inline u16 get_lane_offset(int slot, int rank, int lane)
161{
162 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
163 0x452 * (lane == 8);
164}
165
166static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
167{
168 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
169 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
170}
171
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100172static u32 gav_real(int line, u32 in)
173{
174 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
175 return in;
176}
177
178#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180struct raminfo {
181 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
182 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
183 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
184 u8 density[2][2]; /* [CHANNEL][SLOT] */
185 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
186 int rank_start[2][2][2];
187 u8 cas_latency;
188 u8 board_lane_delay[9];
189 u8 use_ecc;
190 u8 revision;
191 u8 max_supported_clock_speed_index;
192 u8 uma_enabled;
193 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
194 u8 silicon_revision;
195 u8 populated_ranks_mask[2];
196 u8 max_slots_used_in_channel;
197 u8 mode4030[2];
198 u16 avg4044[2];
199 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600200 unsigned int total_memory_mb;
201 unsigned int interleaved_part_mb;
202 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100203
Martin Roth468d02c2019-10-23 21:44:42 -0600204 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100205
206 struct ram_training training;
207 u32 last_500_command[2];
208
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209 u32 delay46_ps[2];
210 u32 delay54_ps[2];
211 u8 revision_flag_1;
212 u8 some_delay_1_cycle_floor;
213 u8 some_delay_2_halfcycles_ceil;
214 u8 some_delay_3_ps_rounded;
215
216 const struct ram_training *cached_training;
217};
218
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200219/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100220timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200221
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100222static void
223write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
224 int flag);
225
226/* OK */
227static u16
228read_500(struct raminfo *info, int channel, u16 addr, int split)
229{
230 u32 val;
231 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200232 MCHBAR32(0x500 + (channel << 10)) = 0;
233 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
234 ;
235 MCHBAR32(0x500 + (channel << 10)) =
236 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
237 + 0xb88 - addr);
238 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
239 ;
240 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100241 return val & ((1 << split) - 1);
242}
243
244/* OK */
245static void
246write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
247 int flag)
248{
249 if (info->last_500_command[channel] == 0x80000000) {
250 info->last_500_command[channel] = 0x40000000;
251 write_500(info, channel, 0, 0xb61, 0, 0);
252 }
Felix Held04be2dd2018-07-29 04:53:22 +0200253 MCHBAR32(0x500 + (channel << 10)) = 0;
254 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
255 ;
256 MCHBAR32(0x504 + (channel << 10)) =
257 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
258 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200259 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200260 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261}
262
263static int rw_test(int rank)
264{
265 const u32 mask = 0xf00fc33c;
266 int ok = 0xff;
267 int i;
268 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800269 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270 sfence();
271 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800272 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100273 sfence();
274 for (i = 0; i < 32; i++) {
275 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 write32p((rank << 28) | (i << 3), pat);
277 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 }
279 sfence();
280 for (i = 0; i < 32; i++) {
281 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
282 int j;
283 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800284 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 for (j = 0; j < 4; j++)
286 if (((val >> (j * 8)) & 0xff) != pat)
287 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 for (j = 0; j < 4; j++)
290 if (((val >> (j * 8)) & 0xff) != pat)
291 ok &= ~(16 << j);
292 }
293 sfence();
294 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800295 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100296 sfence();
297 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100299
300 return ok;
301}
302
303static void
304program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
305{
306 int lane;
307 for (lane = 0; lane < 8; lane++) {
308 write_500(info, channel,
309 base +
310 info->training.
311 lane_timings[2][channel][slot][rank][lane],
312 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
313 write_500(info, channel,
314 base +
315 info->training.
316 lane_timings[3][channel][slot][rank][lane],
317 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
318 }
319}
320
321static void write_26c(int channel, u16 si)
322{
Felix Held04be2dd2018-07-29 04:53:22 +0200323 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
324 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
325 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100326}
327
328static u32 get_580(int channel, u8 addr)
329{
330 u32 ret;
331 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200332 MCHBAR8(0x5ff) = 0x0;
333 MCHBAR8(0x5ff) = 0x80;
334 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
335 MCHBAR8_OR(0x580 + (channel << 10), 1);
336 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
337 ;
338 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100339 return ret;
340}
341
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100342#define NUM_CHANNELS 2
343#define NUM_SLOTS 2
344#define NUM_RANKS 2
345#define RANK_SHIFT 28
346#define CHANNEL_SHIFT 10
347
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100348static void seq9(struct raminfo *info, int channel, int slot, int rank)
349{
350 int i, lane;
351
352 for (i = 0; i < 2; i++)
353 for (lane = 0; lane < 8; lane++)
354 write_500(info, channel,
355 info->training.lane_timings[i +
356 1][channel][slot]
357 [rank][lane], get_timing_register_addr(lane,
358 i + 1,
359 slot,
360 rank),
361 9, 0);
362
363 write_1d0(1, 0x103, 6, 1);
364 for (lane = 0; lane < 8; lane++)
365 write_500(info, channel,
366 info->training.
367 lane_timings[0][channel][slot][rank][lane],
368 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
369
370 for (i = 0; i < 2; i++) {
371 for (lane = 0; lane < 8; lane++)
372 write_500(info, channel,
373 info->training.lane_timings[i +
374 1][channel][slot]
375 [rank][lane], get_timing_register_addr(lane,
376 i + 1,
377 slot,
378 rank),
379 9, 0);
380 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
381 }
382
383 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200384 MCHBAR8(0x5ff) = 0x0;
385 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100386 write_1d0(0x2, 0x142, 3, 1);
387 for (lane = 0; lane < 8; lane++) {
388 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
389 info->training.lane_timings[2][channel][slot][rank][lane] =
390 read_500(info, channel,
391 get_timing_register_addr(lane, 2, slot, rank), 9);
392 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
393 info->training.lane_timings[3][channel][slot][rank][lane] =
394 info->training.lane_timings[2][channel][slot][rank][lane] +
395 0x20;
396 }
397}
398
399static int count_ranks_in_channel(struct raminfo *info, int channel)
400{
401 int slot, rank;
402 int res = 0;
403 for (slot = 0; slot < NUM_SLOTS; slot++)
404 for (rank = 0; rank < NUM_SLOTS; rank++)
405 res += info->populated_ranks[channel][slot][rank];
406 return res;
407}
408
409static void
410config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
411{
412 int add;
413
414 write_1d0(0, 0x178, 7, 1);
415 seq9(info, channel, slot, rank);
416 program_timings(info, 0x80, channel, slot, rank);
417
418 if (channel == 0)
419 add = count_ranks_in_channel(info, 1);
420 else
421 add = 0;
422 if (!s3resume)
423 gav(rw_test(rank + add));
424 program_timings(info, 0x00, channel, slot, rank);
425 if (!s3resume)
426 gav(rw_test(rank + add));
427 if (!s3resume)
428 gav(rw_test(rank + add));
429 write_1d0(0, 0x142, 3, 1);
430 write_1d0(0, 0x103, 6, 1);
431
432 gav(get_580(channel, 0xc | (rank << 5)));
433 gav(read_1d0(0x142, 3));
434
Felix Held04be2dd2018-07-29 04:53:22 +0200435 MCHBAR8(0x5ff) = 0x0;
436 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100437}
438
439static void set_4cf(struct raminfo *info, int channel, u8 val)
440{
441 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
442 write_500(info, channel, val, 0x4cf, 4, 1);
443 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
444 write_500(info, channel, val, 0x659, 4, 1);
445 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
446 write_500(info, channel, val, 0x697, 4, 1);
447}
448
449static void set_334(int zero)
450{
451 int j, k, channel;
452 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
453 u32 vd8[2][16];
454
455 for (channel = 0; channel < NUM_CHANNELS; channel++) {
456 for (j = 0; j < 4; j++) {
457 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
458 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
459 u16 c;
460 if ((j == 0 || j == 3) && zero)
461 c = 0;
462 else if (j == 3)
463 c = 0x5f;
464 else
465 c = 0x5f5f;
466
467 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200468 MCHBAR32(0x138 + 8 * k) =
469 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100470 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200471 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100472 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200473 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100474 }
475
Felix Held22ca8cb2018-07-29 05:09:44 +0200476 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200478 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
479 zero ? 0 : (0x18191819 & lmask);
480 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
481 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
482 zero ? 0 : (a & lmask);
483 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
484 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485 }
486 }
487
Felix Held04be2dd2018-07-29 04:53:22 +0200488 MCHBAR32_OR(0x130, 1);
489 while (MCHBAR8(0x130) & 1)
490 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100491}
492
493static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
494{
495 u32 v;
496 v = read_1d0(addr, split);
497 write_1d0((v & and) | or, addr, split, flag);
498}
499
500static int find_highest_bit_set(u16 val)
501{
502 int i;
503 for (i = 15; i >= 0; i--)
504 if (val & (1 << i))
505 return i;
506 return -1;
507}
508
509static int find_lowest_bit_set32(u32 val)
510{
511 int i;
512 for (i = 0; i < 32; i++)
513 if (val & (1 << i))
514 return i;
515 return -1;
516}
517
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100518enum {
519 DEVICE_TYPE = 2,
520 MODULE_TYPE = 3,
521 DENSITY = 4,
522 RANKS_AND_DQ = 7,
523 MEMORY_BUS_WIDTH = 8,
524 TIMEBASE_DIVIDEND = 10,
525 TIMEBASE_DIVISOR = 11,
526 CYCLETIME = 12,
527
528 CAS_LATENCIES_LSB = 14,
529 CAS_LATENCIES_MSB = 15,
530 CAS_LATENCY_TIME = 16,
531 THERMAL_AND_REFRESH = 31,
532 REFERENCE_RAW_CARD_USED = 62,
533 RANK1_ADDRESS_MAPPING = 63
534};
535
536static void calculate_timings(struct raminfo *info)
537{
Martin Roth468d02c2019-10-23 21:44:42 -0600538 unsigned int cycletime;
539 unsigned int cas_latency_time;
540 unsigned int supported_cas_latencies;
541 unsigned int channel, slot;
542 unsigned int clock_speed_index;
543 unsigned int min_cas_latency;
544 unsigned int cas_latency;
545 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100546
547 /* Find common CAS latency */
548 supported_cas_latencies = 0x3fe;
549 for (channel = 0; channel < NUM_CHANNELS; channel++)
550 for (slot = 0; slot < NUM_SLOTS; slot++)
551 if (info->populated_ranks[channel][slot][0])
552 supported_cas_latencies &=
553 2 *
554 (info->
555 spd[channel][slot][CAS_LATENCIES_LSB] |
556 (info->
557 spd[channel][slot][CAS_LATENCIES_MSB] <<
558 8));
559
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100560 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100561
562 cycletime = min_cycletime[max_clock_index];
563 cas_latency_time = min_cas_latency_time[max_clock_index];
564
565 for (channel = 0; channel < NUM_CHANNELS; channel++)
566 for (slot = 0; slot < NUM_SLOTS; slot++)
567 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600568 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100569 timebase =
570 1000 *
571 info->
572 spd[channel][slot][TIMEBASE_DIVIDEND] /
573 info->spd[channel][slot][TIMEBASE_DIVISOR];
574 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100575 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100576 timebase *
577 info->spd[channel][slot][CYCLETIME]);
578 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100579 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100580 timebase *
581 info->
582 spd[channel][slot][CAS_LATENCY_TIME]);
583 }
Jacob Garber3c193822019-06-10 18:23:32 -0600584 if (cycletime > min_cycletime[0])
585 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100586 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
587 if (cycletime == min_cycletime[clock_speed_index])
588 break;
589 if (cycletime > min_cycletime[clock_speed_index]) {
590 clock_speed_index--;
591 cycletime = min_cycletime[clock_speed_index];
592 break;
593 }
594 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100595 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100596 cas_latency = 0;
597 while (supported_cas_latencies) {
598 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
599 if (cas_latency <= min_cas_latency)
600 break;
601 supported_cas_latencies &=
602 ~(1 << find_highest_bit_set(supported_cas_latencies));
603 }
604
605 if (cas_latency != min_cas_latency && clock_speed_index)
606 clock_speed_index--;
607
608 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
609 die("Couldn't configure DRAM");
610 info->clock_speed_index = clock_speed_index;
611 info->cas_latency = cas_latency;
612}
613
614static void program_base_timings(struct raminfo *info)
615{
Martin Roth468d02c2019-10-23 21:44:42 -0600616 unsigned int channel;
617 unsigned int slot, rank, lane;
618 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100619 int i;
620
621 extended_silicon_revision = info->silicon_revision;
622 if (info->silicon_revision == 0)
623 for (channel = 0; channel < NUM_CHANNELS; channel++)
624 for (slot = 0; slot < NUM_SLOTS; slot++)
625 if ((info->
626 spd[channel][slot][MODULE_TYPE] & 0xF) ==
627 3)
628 extended_silicon_revision = 4;
629
630 for (channel = 0; channel < NUM_CHANNELS; channel++) {
631 for (slot = 0; slot < NUM_SLOTS; slot++)
632 for (rank = 0; rank < NUM_SLOTS; rank++) {
633 int card_timing_2;
634 if (!info->populated_ranks[channel][slot][rank])
635 continue;
636
637 for (lane = 0; lane < 9; lane++) {
638 int tm_reg;
639 int card_timing;
640
641 card_timing = 0;
642 if ((info->
643 spd[channel][slot][MODULE_TYPE] &
644 0xF) == 3) {
645 int reference_card;
646 reference_card =
647 info->
648 spd[channel][slot]
649 [REFERENCE_RAW_CARD_USED] &
650 0x1f;
651 if (reference_card == 3)
652 card_timing =
653 u16_ffd1188[0][lane]
654 [info->
655 clock_speed_index];
656 if (reference_card == 5)
657 card_timing =
658 u16_ffd1188[1][lane]
659 [info->
660 clock_speed_index];
661 }
662
663 info->training.
664 lane_timings[0][channel][slot][rank]
665 [lane] =
666 u8_FFFD1218[info->
667 clock_speed_index];
668 info->training.
669 lane_timings[1][channel][slot][rank]
670 [lane] = 256;
671
672 for (tm_reg = 2; tm_reg < 4; tm_reg++)
673 info->training.
674 lane_timings[tm_reg]
675 [channel][slot][rank][lane]
676 =
677 u8_FFFD1240[channel]
678 [extended_silicon_revision]
679 [lane][2 * slot +
680 rank][info->
681 clock_speed_index]
682 + info->max4048[channel]
683 +
684 u8_FFFD0C78[channel]
685 [extended_silicon_revision]
686 [info->
687 mode4030[channel]][slot]
688 [rank][info->
689 clock_speed_index]
690 + card_timing;
691 for (tm_reg = 0; tm_reg < 4; tm_reg++)
692 write_500(info, channel,
693 info->training.
694 lane_timings[tm_reg]
695 [channel][slot][rank]
696 [lane],
697 get_timing_register_addr
698 (lane, tm_reg, slot,
699 rank), 9, 0);
700 }
701
702 card_timing_2 = 0;
703 if (!(extended_silicon_revision != 4
704 || (info->
705 populated_ranks_mask[channel] & 5) ==
706 5)) {
707 if ((info->
708 spd[channel][slot]
709 [REFERENCE_RAW_CARD_USED] & 0x1F)
710 == 3)
711 card_timing_2 =
712 u16_FFFE0EB8[0][info->
713 clock_speed_index];
714 if ((info->
715 spd[channel][slot]
716 [REFERENCE_RAW_CARD_USED] & 0x1F)
717 == 5)
718 card_timing_2 =
719 u16_FFFE0EB8[1][info->
720 clock_speed_index];
721 }
722
723 for (i = 0; i < 3; i++)
724 write_500(info, channel,
725 (card_timing_2 +
726 info->max4048[channel]
727 +
728 u8_FFFD0EF8[channel]
729 [extended_silicon_revision]
730 [info->
731 mode4030[channel]][info->
732 clock_speed_index]),
733 u16_fffd0c50[i][slot][rank],
734 8, 1);
735 write_500(info, channel,
736 (info->max4048[channel] +
737 u8_FFFD0C78[channel]
738 [extended_silicon_revision][info->
739 mode4030
740 [channel]]
741 [slot][rank][info->
742 clock_speed_index]),
743 u16_fffd0c70[slot][rank], 7, 1);
744 }
745 if (!info->populated_ranks_mask[channel])
746 continue;
747 for (i = 0; i < 3; i++)
748 write_500(info, channel,
749 (info->max4048[channel] +
750 info->avg4044[channel]
751 +
752 u8_FFFD17E0[channel]
753 [extended_silicon_revision][info->
754 mode4030
755 [channel]][info->
756 clock_speed_index]),
757 u16_fffd0c68[i], 8, 1);
758 }
759}
760
761static unsigned int fsbcycle_ps(struct raminfo *info)
762{
763 return 900000 / info->fsb_frequency;
764}
765
766/* The time of DDR transfer in ps. */
767static unsigned int halfcycle_ps(struct raminfo *info)
768{
769 return 3750 / (info->clock_speed_index + 3);
770}
771
772/* The time of clock cycle in ps. */
773static unsigned int cycle_ps(struct raminfo *info)
774{
775 return 2 * halfcycle_ps(info);
776}
777
778/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600779static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100780{
781 return (info->clock_speed_index + 3) * 120;
782}
783
784/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600785static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786{
787 return 100 * frequency_11(info) / 9;
788}
789
Martin Roth468d02c2019-10-23 21:44:42 -0600790static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100791{
792 return (frequency_11(info) * 2) * ps / 900000;
793}
794
Martin Roth468d02c2019-10-23 21:44:42 -0600795static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100796{
797 return (frequency_11(info)) * ns / 900;
798}
799
800static void compute_derived_timings(struct raminfo *info)
801{
Martin Roth468d02c2019-10-23 21:44:42 -0600802 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100803 int extended_silicon_revision;
804 int some_delay_1_ps;
805 int some_delay_2_ps;
806 int some_delay_2_halfcycles_ceil;
807 int some_delay_2_halfcycles_floor;
808 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100809 int some_delay_3_ps_rounded;
810 int some_delay_1_cycle_ceil;
811 int some_delay_1_cycle_floor;
812
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100813 some_delay_3_ps_rounded = 0;
814 extended_silicon_revision = info->silicon_revision;
815 if (!info->silicon_revision)
816 for (channel = 0; channel < NUM_CHANNELS; channel++)
817 for (slot = 0; slot < NUM_SLOTS; slot++)
818 if ((info->
819 spd[channel][slot][MODULE_TYPE] & 0xF) ==
820 3)
821 extended_silicon_revision = 4;
822 if (info->board_lane_delay[7] < 5)
823 info->board_lane_delay[7] = 5;
824 info->revision_flag_1 = 2;
825 if (info->silicon_revision == 2 || info->silicon_revision == 3)
826 info->revision_flag_1 = 0;
827 if (info->revision < 16)
828 info->revision_flag_1 = 0;
829
830 if (info->revision < 8)
831 info->revision_flag_1 = 0;
832 if (info->revision >= 8 && (info->silicon_revision == 0
833 || info->silicon_revision == 1))
834 some_delay_2_ps = 735;
835 else
836 some_delay_2_ps = 750;
837
838 if (info->revision >= 0x10 && (info->silicon_revision == 0
839 || info->silicon_revision == 1))
840 some_delay_1_ps = 3929;
841 else
842 some_delay_1_ps = 3490;
843
844 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
845 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
846 if (some_delay_1_ps % cycle_ps(info))
847 some_delay_1_cycle_ceil++;
848 else
849 some_delay_1_cycle_floor--;
850 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
851 if (info->revision_flag_1)
852 some_delay_2_ps = halfcycle_ps(info) >> 6;
853 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100854 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100855 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
856 375;
857 some_delay_3_ps =
858 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
859 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200860 if (some_delay_3_ps >= 150) {
861 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100862 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200863 some_delay_3_ps_rounded =
864 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
865 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100866 }
867 some_delay_2_halfcycles_ceil =
868 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
869 2 * (some_delay_1_cycle_ceil - 1);
870 if (info->revision_flag_1 && some_delay_3_ps < 150)
871 some_delay_2_halfcycles_ceil++;
872 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
873 if (info->revision < 0x10)
874 some_delay_2_halfcycles_floor =
875 some_delay_2_halfcycles_ceil - 1;
876 if (!info->revision_flag_1)
877 some_delay_2_halfcycles_floor++;
878 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
879 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
880 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
881 || (info->populated_ranks[1][0][0]
882 && info->populated_ranks[1][1][0]))
883 info->max_slots_used_in_channel = 2;
884 else
885 info->max_slots_used_in_channel = 1;
886 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200887 MCHBAR32(0x244 + (channel << 10)) =
888 ((info->revision < 8) ? 1 : 0x200) |
889 ((2 - info->max_slots_used_in_channel) << 17) |
890 (channel << 21) |
891 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 if (info->max_slots_used_in_channel == 1) {
893 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
894 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
895 } else {
896 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 */
897 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
898 || (count_ranks_in_channel(info, 1) ==
899 2)) ? 2 : 3;
900 }
901 for (channel = 0; channel < NUM_CHANNELS; channel++) {
902 int max_of_unk;
903 int min_of_unk_2;
904
905 int i, count;
906 int sum;
907
908 if (!info->populated_ranks_mask[channel])
909 continue;
910
911 max_of_unk = 0;
912 min_of_unk_2 = 32767;
913
914 sum = 0;
915 count = 0;
916 for (i = 0; i < 3; i++) {
917 int unk1;
918 if (info->revision < 8)
919 unk1 =
920 u8_FFFD1891[0][channel][info->
921 clock_speed_index]
922 [i];
923 else if (!
924 (info->revision >= 0x10
925 || info->revision_flag_1))
926 unk1 =
927 u8_FFFD1891[1][channel][info->
928 clock_speed_index]
929 [i];
930 else
931 unk1 = 0;
932 for (slot = 0; slot < NUM_SLOTS; slot++)
933 for (rank = 0; rank < NUM_RANKS; rank++) {
934 int a = 0;
935 int b = 0;
936
937 if (!info->
938 populated_ranks[channel][slot]
939 [rank])
940 continue;
941 if (extended_silicon_revision == 4
942 && (info->
943 populated_ranks_mask[channel] &
944 5) != 5) {
945 if ((info->
946 spd[channel][slot]
947 [REFERENCE_RAW_CARD_USED] &
948 0x1F) == 3) {
949 a = u16_ffd1178[0]
950 [info->
951 clock_speed_index];
952 b = u16_fe0eb8[0][info->
953 clock_speed_index];
954 } else
955 if ((info->
956 spd[channel][slot]
957 [REFERENCE_RAW_CARD_USED]
958 & 0x1F) == 5) {
959 a = u16_ffd1178[1]
960 [info->
961 clock_speed_index];
962 b = u16_fe0eb8[1][info->
963 clock_speed_index];
964 }
965 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100966 min_of_unk_2 = MIN(min_of_unk_2, a);
967 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100968 if (rank == 0) {
969 sum += a;
970 count++;
971 }
972 {
973 int t;
974 t = b +
975 u8_FFFD0EF8[channel]
976 [extended_silicon_revision]
977 [info->
978 mode4030[channel]][info->
979 clock_speed_index];
980 if (unk1 >= t)
981 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100982 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100983 unk1 - t);
984 }
985 }
986 {
987 int t =
988 u8_FFFD17E0[channel]
989 [extended_silicon_revision][info->
990 mode4030
991 [channel]]
992 [info->clock_speed_index] + min_of_unk_2;
993 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100994 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100995 }
996 }
997
Jacob Garber64fb4a32019-06-10 17:29:18 -0600998 if (count == 0)
999 die("No memory ranks found for channel %u\n", channel);
1000
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001001 info->avg4044[channel] = sum / count;
1002 info->max4048[channel] = max_of_unk;
1003 }
1004}
1005
1006static void jedec_read(struct raminfo *info,
1007 int channel, int slot, int rank,
1008 int total_rank, u8 addr3, unsigned int value)
1009{
1010 /* Handle mirrored mapping. */
1011 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001012 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1013 ((addr3 >> 1) & 0x10);
1014 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1015 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001016
1017 /* Handle mirrored mapping. */
1018 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1019 value =
1020 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1021 << 1);
1022
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001023 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001024
Felix Held04be2dd2018-07-29 04:53:22 +02001025 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1026 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001027
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001028 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001029}
1030
1031enum {
1032 MR1_RZQ12 = 512,
1033 MR1_RZQ2 = 64,
1034 MR1_RZQ4 = 4,
1035 MR1_ODS34OHM = 2
1036};
1037
1038enum {
1039 MR0_BT_INTERLEAVED = 8,
1040 MR0_DLL_RESET_ON = 256
1041};
1042
1043enum {
1044 MR2_RTT_WR_DISABLED = 0,
1045 MR2_RZQ2 = 1 << 10
1046};
1047
1048static void jedec_init(struct raminfo *info)
1049{
1050 int write_recovery;
1051 int channel, slot, rank;
1052 int total_rank;
1053 int dll_on;
1054 int self_refresh_temperature;
1055 int auto_self_refresh;
1056
1057 auto_self_refresh = 1;
1058 self_refresh_temperature = 1;
1059 if (info->board_lane_delay[3] <= 10) {
1060 if (info->board_lane_delay[3] <= 8)
1061 write_recovery = info->board_lane_delay[3] - 4;
1062 else
1063 write_recovery = 5;
1064 } else {
1065 write_recovery = 6;
1066 }
1067 FOR_POPULATED_RANKS {
1068 auto_self_refresh &=
1069 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1070 self_refresh_temperature &=
1071 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1072 }
1073 if (auto_self_refresh == 1)
1074 self_refresh_temperature = 0;
1075
1076 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1077 || (info->populated_ranks[0][0][0]
1078 && info->populated_ranks[0][1][0])
1079 || (info->populated_ranks[1][0][0]
1080 && info->populated_ranks[1][1][0]));
1081
1082 total_rank = 0;
1083
1084 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1085 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1086 int rzq_reg58e;
1087
1088 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1089 rzq_reg58e = 64;
1090 rtt = MR1_RZQ2;
1091 if (info->clock_speed_index != 0) {
1092 rzq_reg58e = 4;
1093 if (info->populated_ranks_mask[channel] == 3)
1094 rtt = MR1_RZQ4;
1095 }
1096 } else {
1097 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1098 rtt = MR1_RZQ12;
1099 rzq_reg58e = 64;
1100 rtt_wr = MR2_RZQ2;
1101 } else {
1102 rzq_reg58e = 4;
1103 rtt = MR1_RZQ4;
1104 }
1105 }
1106
Felix Held04be2dd2018-07-29 04:53:22 +02001107 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1108 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1109 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1110 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1111 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001112
1113 for (slot = 0; slot < NUM_SLOTS; slot++)
1114 for (rank = 0; rank < NUM_RANKS; rank++)
1115 if (info->populated_ranks[channel][slot][rank]) {
1116 jedec_read(info, channel, slot, rank,
1117 total_rank, 0x28,
1118 rtt_wr | (info->
1119 clock_speed_index
1120 << 3)
1121 | (auto_self_refresh << 6) |
1122 (self_refresh_temperature <<
1123 7));
1124 jedec_read(info, channel, slot, rank,
1125 total_rank, 0x38, 0);
1126 jedec_read(info, channel, slot, rank,
1127 total_rank, 0x18,
1128 rtt | MR1_ODS34OHM);
1129 jedec_read(info, channel, slot, rank,
1130 total_rank, 6,
1131 (dll_on << 12) |
1132 (write_recovery << 9)
1133 | ((info->cas_latency - 4) <<
1134 4) | MR0_BT_INTERLEAVED |
1135 MR0_DLL_RESET_ON);
1136 total_rank++;
1137 }
1138 }
1139}
1140
1141static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1142{
Martin Roth468d02c2019-10-23 21:44:42 -06001143 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001144 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1145 unsigned int channel_0_non_interleaved;
1146
1147 FOR_ALL_RANKS {
1148 if (info->populated_ranks[channel][slot][rank]) {
1149 total_mb[channel] +=
1150 pre_jedec ? 256 : (256 << info->
1151 density[channel][slot] >> info->
1152 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001153 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1154 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1155 (info->is_x16_module[channel][slot] |
1156 ((info->density[channel][slot] + 1) << 1))) |
1157 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001158 }
Felix Held04be2dd2018-07-29 04:53:22 +02001159 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1160 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 }
1162
1163 info->total_memory_mb = total_mb[0] + total_mb[1];
1164
1165 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001166 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 info->non_interleaved_part_mb =
1168 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1169 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001170 MCHBAR32(0x100) = channel_0_non_interleaved |
1171 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001173 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174}
1175
1176static void program_board_delay(struct raminfo *info)
1177{
1178 int cas_latency_shift;
1179 int some_delay_ns;
1180 int some_delay_3_half_cycles;
1181
Martin Roth468d02c2019-10-23 21:44:42 -06001182 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183 int high_multiplier;
1184 int lane_3_delay;
1185 int cas_latency_derived;
1186
1187 high_multiplier = 0;
1188 some_delay_ns = 200;
1189 some_delay_3_half_cycles = 4;
1190 cas_latency_shift = info->silicon_revision == 0
1191 || info->silicon_revision == 1 ? 1 : 0;
1192 if (info->revision < 8) {
1193 some_delay_ns = 600;
1194 cas_latency_shift = 0;
1195 }
1196 {
1197 int speed_bit;
1198 speed_bit =
1199 ((info->clock_speed_index > 1
1200 || (info->silicon_revision != 2
1201 && info->silicon_revision != 3))) ^ (info->revision >=
1202 0x10);
1203 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1204 3, 1);
1205 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1206 3, 1);
1207 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1208 && (info->silicon_revision == 2
1209 || info->silicon_revision == 3))
1210 rmw_1d0(0x116, 5, 2, 4, 1);
1211 }
Felix Held04be2dd2018-07-29 04:53:22 +02001212 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1213 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214
Felix Held04be2dd2018-07-29 04:53:22 +02001215 MCHBAR8(0x124) = info->board_lane_delay[4] +
1216 ((frequency_01(info) + 999) / 1000);
1217 MCHBAR16(0x125) = 0x1360;
1218 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001219 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001220 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001221 high_multiplier = 1;
1222 some_delay_2_half_cycles = ps_to_halfcycles(info,
1223 ((3 *
1224 fsbcycle_ps(info))
1225 >> 1) +
1226 (halfcycle_ps(info)
1227 *
1228 reg178_min[info->
1229 clock_speed_index]
1230 >> 6)
1231 +
1232 4 *
1233 halfcycle_ps(info)
1234 + 2230);
1235 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001236 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001237 (frequency_11(info) * 2) * (28 -
1238 some_delay_2_half_cycles) /
1239 (frequency_11(info) * 2 -
1240 4 * (info->fsb_frequency))) >> 3, 7);
1241 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001242 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001243 some_delay_3_half_cycles = 3;
1244 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001245 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1246 MCHBAR32(0x224 + (channel << 10)) =
1247 (info->max_slots_used_in_channel - 1) |
1248 ((info->cas_latency - 5 - info->clock_speed_index)
1249 << 21) | ((info->max_slots_used_in_channel +
1250 info->cas_latency - cas_latency_shift - 4) << 16) |
1251 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1252 ((info->cas_latency - info->clock_speed_index +
1253 info->max_slots_used_in_channel - 6) << 8);
1254 MCHBAR32(0x228 + (channel << 10)) =
1255 info->max_slots_used_in_channel;
1256 MCHBAR8(0x239 + (channel << 10)) = 32;
1257 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1258 (some_delay_3_half_cycles << 25) | 0x840000;
1259 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1260 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1261 MCHBAR32(0x24c + (channel << 10)) =
1262 ((!!info->clock_speed_index) << 17) |
1263 (((2 + info->clock_speed_index -
1264 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001265
Felix Held04be2dd2018-07-29 04:53:22 +02001266 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1267 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1268 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001269
1270 write_500(info, channel,
1271 ((!info->populated_ranks[channel][1][1])
1272 | (!info->populated_ranks[channel][1][0] << 1)
1273 | (!info->populated_ranks[channel][0][1] << 2)
1274 | (!info->populated_ranks[channel][0][0] << 3)),
1275 0x4c9, 4, 1);
1276 }
1277
Felix Held22ca8cb2018-07-29 05:09:44 +02001278 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279 {
1280 u8 freq_divisor = 2;
1281 if (info->fsb_frequency == frequency_11(info))
1282 freq_divisor = 3;
1283 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1284 freq_divisor = 1;
1285 else
1286 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001287 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001288 }
1289
1290 if (info->board_lane_delay[3] <= 10) {
1291 if (info->board_lane_delay[3] <= 8)
1292 lane_3_delay = info->board_lane_delay[3];
1293 else
1294 lane_3_delay = 10;
1295 } else {
1296 lane_3_delay = 12;
1297 }
1298 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1299 if (info->clock_speed_index > 1)
1300 cas_latency_derived++;
1301 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001302 MCHBAR32(0x240 + (channel << 10)) =
1303 ((info->clock_speed_index == 0) * 0x11000) |
1304 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1305 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001306 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1307 0x609, 6, 1);
1308 write_500(info, channel,
1309 info->clock_speed_index + 2 * info->cas_latency - 7,
1310 0x601, 6, 1);
1311
Felix Held04be2dd2018-07-29 04:53:22 +02001312 MCHBAR32(0x250 + (channel << 10)) =
1313 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1314 (info->board_lane_delay[7] << 2) |
1315 (info->board_lane_delay[4] << 16) |
1316 (info->board_lane_delay[1] << 25) |
1317 (info->board_lane_delay[1] << 29) | 1;
1318 MCHBAR32(0x254 + (channel << 10)) =
1319 (info->board_lane_delay[1] >> 3) |
1320 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1321 0x80 | (info->board_lane_delay[6] << 1) |
1322 (info->board_lane_delay[2] << 28) |
1323 (cas_latency_derived << 16) | 0x4700000;
1324 MCHBAR32(0x258 + (channel << 10)) =
1325 ((info->board_lane_delay[5] + info->clock_speed_index +
1326 9) << 12) | ((info->clock_speed_index -
1327 info->cas_latency + 12) << 8) |
1328 (info->board_lane_delay[2] << 17) |
1329 (info->board_lane_delay[4] << 24) | 0x47;
1330 MCHBAR32(0x25c + (channel << 10)) =
1331 (info->board_lane_delay[1] << 1) |
1332 (info->board_lane_delay[0] << 8) | 0x1da50000;
1333 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1334 MCHBAR8(0x5f8 + (channel << 10)) =
1335 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001336 }
1337
1338 program_modules_memory_map(info, 1);
1339
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001340 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001341 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1342 MCHBAR16_OR(0x612, 0x100);
1343 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001344 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001345 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001346 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001347 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001348 }
1349}
1350
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001351#define DEFAULT_PCI_MMIO_SIZE 2048
1352#define HOST_BRIDGE PCI_DEVFN(0, 0)
1353
1354static unsigned int get_mmio_size(void)
1355{
1356 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001357 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001358
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001359 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001360 if (dev)
1361 cfg = dev->chip_info;
1362
1363 /* If this is zero, it just means devicetree.cb didn't set it */
1364 if (!cfg || cfg->pci_mmio_size == 0)
1365 return DEFAULT_PCI_MMIO_SIZE;
1366 else
1367 return cfg->pci_mmio_size;
1368}
1369
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001370static void program_total_memory_map(struct raminfo *info)
1371{
Angel Pons9333b742020-07-22 16:04:15 +02001372 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001373 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001374 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001375 unsigned int uma_base_igd;
1376 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001377 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378 int memory_remap;
1379 unsigned int memory_map[8];
1380 int i;
1381 unsigned int current_limit;
1382 unsigned int tseg_base;
1383 int uma_size_igd = 0, uma_size_gtt = 0;
1384
1385 memset(memory_map, 0, sizeof(memory_map));
1386
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001388 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001389 gav(t);
1390 const int uma_sizes_gtt[16] =
1391 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1392 /* Igd memory */
1393 const int uma_sizes_igd[16] = {
1394 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1395 256, 512
1396 };
1397
1398 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1399 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1400 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001402 mmio_size = get_mmio_size();
1403
Angel Pons9333b742020-07-22 16:04:15 +02001404 tom = info->total_memory_mb;
1405 if (tom == 4096)
1406 tom = 4032;
1407 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1408 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1409 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001410 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001411 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001413 remap_base = MAX(4096, touud);
1414 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415 }
Angel Pons9333b742020-07-22 16:04:15 +02001416 if (touud > 4096)
1417 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418 quickpath_reserved = 0;
1419
Angel Pons3ab19b32020-07-22 16:29:54 +02001420 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001421
Jacob Garber975a7e32019-06-10 16:32:47 -06001422 gav(t);
1423
1424 if (t & 0x800) {
1425 u32 shift = t >> 20;
1426 if (shift == 0)
1427 die("Quickpath value is 0\n");
1428 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001430
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001431 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001432 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001433
Angel Pons9333b742020-07-22 16:04:15 +02001434 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001435 uma_base_gtt = uma_base_igd - uma_size_gtt;
1436 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1437 if (!memory_remap)
1438 tseg_base -= quickpath_reserved;
1439 tseg_base = ALIGN_DOWN(tseg_base, 8);
1440
Angel Pons16fe1e02020-07-22 16:12:33 +02001441 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1442 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001444 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1445 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001447 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448
1449 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001450 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1451 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001453 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454
1455 current_limit = 0;
1456 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1457 memory_map[1] = 4096;
1458 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001459 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001460 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1462 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001463 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464 }
1465}
1466
1467static void collect_system_info(struct raminfo *info)
1468{
1469 u32 capid0[3];
1470 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001471 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472
1473 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001474 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1475 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477 if (!info->memory_reserved_for_heci_mb) {
1478 /* Wait for ME to be ready */
1479 intel_early_me_init();
1480 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1481 }
1482
Angel Ponsb600d412021-01-16 16:33:48 +01001483 for (i = 0; i < 3; i++) {
1484 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1485 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1486 }
1487 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1488 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1489 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1490
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001491 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1492
1493 if ((capid0[1] >> 11) & 1)
1494 info->uma_enabled = 0;
1495 else
1496 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001497 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1499 info->silicon_revision = 0;
1500
1501 if (capid0[2] & 2) {
1502 info->silicon_revision = 0;
1503 info->max_supported_clock_speed_index = 2;
1504 for (channel = 0; channel < NUM_CHANNELS; channel++)
1505 if (info->populated_ranks[channel][0][0]
1506 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1507 3) {
1508 info->silicon_revision = 2;
1509 info->max_supported_clock_speed_index = 1;
1510 }
1511 } else {
1512 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1513 case 1:
1514 case 2:
1515 info->silicon_revision = 3;
1516 break;
1517 case 3:
1518 info->silicon_revision = 0;
1519 break;
1520 case 0:
1521 info->silicon_revision = 2;
1522 break;
1523 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001524 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001525 case 0x40:
1526 info->silicon_revision = 0;
1527 break;
1528 case 0x48:
1529 info->silicon_revision = 1;
1530 break;
1531 }
1532 }
1533}
1534
1535static void write_training_data(struct raminfo *info)
1536{
1537 int tm, channel, slot, rank, lane;
1538 if (info->revision < 8)
1539 return;
1540
1541 for (tm = 0; tm < 4; tm++)
1542 for (channel = 0; channel < NUM_CHANNELS; channel++)
1543 for (slot = 0; slot < NUM_SLOTS; slot++)
1544 for (rank = 0; rank < NUM_RANKS; rank++)
1545 for (lane = 0; lane < 9; lane++)
1546 write_500(info, channel,
1547 info->
1548 cached_training->
1549 lane_timings[tm]
1550 [channel][slot][rank]
1551 [lane],
1552 get_timing_register_addr
1553 (lane, tm, slot,
1554 rank), 9, 0);
1555 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1556 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1557}
1558
1559static void dump_timings(struct raminfo *info)
1560{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001561 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001562 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001563 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001564 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001565 slot, rank);
1566 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001567 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001569 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570 read_500(info, channel,
1571 get_timing_register_addr
1572 (lane, i, slot, rank),
1573 9),
1574 info->training.
1575 lane_timings[i][channel][slot][rank]
1576 [lane]);
1577 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001578 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 }
1580 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001581 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001583 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001584 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585}
1586
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001587/* Read timings and other registers that need to be restored verbatim and
1588 put them to CBMEM.
1589 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001590static void save_timings(struct raminfo *info)
1591{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001593 int channel, slot, rank, lane, i;
1594
1595 train = info->training;
1596 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1597 for (i = 0; i < 4; i++)
1598 train.lane_timings[i][channel][slot][rank][lane] =
1599 read_500(info, channel,
1600 get_timing_register_addr(lane, i, slot,
1601 rank), 9);
1602 train.reg_178 = read_1d0(0x178, 7);
1603 train.reg_10b = read_1d0(0x10b, 6);
1604
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001605 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1606 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001607 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001608 train.reg274265[channel][0] = reg32 >> 16;
1609 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001610 train.reg274265[channel][2] =
1611 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612 }
Felix Held04be2dd2018-07-29 04:53:22 +02001613 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1614 train.reg_6dc = MCHBAR32(0x6dc);
1615 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001616
Arthur Heymansb3282092019-04-14 17:53:28 +02001617 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1618 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001619
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001621 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1622 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001623}
1624
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001625static const struct ram_training *get_cached_training(void)
1626{
Shelley Chenad9cd682020-07-23 16:10:52 -07001627 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1628 MRC_CACHE_VERSION,
1629 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001630}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001631
1632/* FIXME: add timeout. */
1633static void wait_heci_ready(void)
1634{
Felix Held04be2dd2018-07-29 04:53:22 +02001635 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1636 ;
Angel Ponseb537932020-09-14 19:18:11 +02001637
1638 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639}
1640
1641/* FIXME: add timeout. */
1642static void wait_heci_cb_avail(int len)
1643{
1644 union {
1645 struct mei_csr csr;
1646 u32 raw;
1647 } csr;
1648
Felix Held22ca8cb2018-07-29 05:09:44 +02001649 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1650 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651
Angel Ponseb537932020-09-14 19:18:11 +02001652 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001653 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001654 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1655 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656}
1657
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001658static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659{
1660 int len = (head->length + 3) / 4;
1661 int i;
1662
1663 wait_heci_cb_avail(len + 1);
1664
1665 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001666 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001668 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001670 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1671 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672}
1673
Angel Ponseb537932020-09-14 19:18:11 +02001674static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001675{
1676 struct mei_header head;
1677 int maxlen;
1678
1679 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001680 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681
1682 while (len) {
1683 int cur = len;
1684 if (cur > maxlen) {
1685 cur = maxlen;
1686 head.is_complete = 0;
1687 } else
1688 head.is_complete = 1;
1689 head.length = cur;
1690 head.reserved = 0;
1691 head.client_address = clientaddress;
1692 head.host_address = hostaddress;
1693 send_heci_packet(&head, (u32 *) msg);
1694 len -= cur;
1695 msg += cur;
1696 }
1697}
1698
1699/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001700static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001701{
1702 union {
1703 struct mei_csr csr;
1704 u32 raw;
1705 } csr;
1706 int i = 0;
1707
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001708 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001710 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001711 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1712
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001713 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001715 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 *packet_size = 0;
1717 return 0;
1718 }
Angel Ponseb537932020-09-14 19:18:11 +02001719 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001720 *packet_size = 0;
1721 return -1;
1722 }
1723
Angel Ponseb537932020-09-14 19:18:11 +02001724 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001725 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001726 } while (((head->length + 3) >> 2) >
1727 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001728
1729 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 *packet_size = head->length;
1732 if (!csr.csr.ready)
1733 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001734 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735 return 0;
1736}
1737
1738/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001739static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740{
1741 struct mei_header head;
1742 int current_position;
1743
1744 current_position = 0;
1745 while (1) {
1746 u32 current_size;
1747 current_size = *message_size - current_position;
1748 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001749 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750 &current_size) == -1)
1751 break;
1752 if (!current_size)
1753 break;
1754 current_position += current_size;
1755 if (head.is_complete) {
1756 *message_size = current_position;
1757 return 0;
1758 }
1759
1760 if (current_position >= *message_size)
1761 break;
1762 }
1763 *message_size = 0;
1764 return -1;
1765}
1766
Angel Pons55f11e22020-09-14 19:06:53 +02001767static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001768{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001769 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001770 u8 group_id;
1771 u8 command;
1772 u8 reserved;
1773 u8 result;
1774 u8 field2;
1775 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001776 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001777
1778 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1779 reply.command = 0;
1780
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001781 struct uma_message {
1782 u8 group_id;
1783 u8 cmd;
1784 u8 reserved;
1785 u8 result;
1786 u32 c2;
1787 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001788 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001789 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001790 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001791 .group_id = 0,
1792 .cmd = MKHI_SET_UMA,
1793 .reserved = 0,
1794 .result = 0,
1795 .c2 = 0x82,
1796 .heci_uma_addr = heci_uma_addr,
1797 .heci_uma_size = heci_uma_size,
1798 .c3 = 0,
1799 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001800 u32 reply_size;
1801
Angel Ponseb537932020-09-14 19:18:11 +02001802 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001803
1804 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001805 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806 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{
Angel Pons298d34d2020-09-14 18:58:53 +02001814 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001815 return;
1816
Angel Pons36592bf2020-09-14 18:52:44 +02001817 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001818 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001819 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001820 info->memory_reserved_for_heci_mb)) << 20;
1821
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001822 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001823 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001824 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001825 write32(DEFAULT_RCBA + 0x14, read32(DEFAULT_RCBA + 0x14) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001826 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001827 write32(DEFAULT_RCBA + 0x20, read32(DEFAULT_RCBA + 0x20) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001828 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001829 write32(DEFAULT_RCBA + 0x30, read32(DEFAULT_RCBA + 0x30) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001830 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001831 write32(DEFAULT_RCBA + 0x40, read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832
Angel Ponseb537932020-09-14 19:18:11 +02001833 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001834 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001835
Felix Held04be2dd2018-07-29 04:53:22 +02001836 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
Angel Pons3b264d02020-09-15 00:25:49 +02001837 DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001838 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 }
1840
Felix Held04be2dd2018-07-29 04:53:22 +02001841 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842
Angel Pons55f11e22020-09-14 19:06:53 +02001843 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001845 pci_write_config32(HECIDEV, 0x10, 0x0);
1846 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847}
1848
1849static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1850{
1851 int ranks_in_channel;
1852 ranks_in_channel = info->populated_ranks[channel][0][0]
1853 + info->populated_ranks[channel][0][1]
1854 + info->populated_ranks[channel][1][0]
1855 + info->populated_ranks[channel][1][1];
1856
1857 /* empty channel */
1858 if (ranks_in_channel == 0)
1859 return 1;
1860
1861 if (ranks_in_channel != ranks)
1862 return 0;
1863 /* single slot */
1864 if (info->populated_ranks[channel][0][0] !=
1865 info->populated_ranks[channel][1][0])
1866 return 1;
1867 if (info->populated_ranks[channel][0][1] !=
1868 info->populated_ranks[channel][1][1])
1869 return 1;
1870 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1871 return 0;
1872 if (info->density[channel][0] != info->density[channel][1])
1873 return 0;
1874 return 1;
1875}
1876
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001877static void read_4090(struct raminfo *info)
1878{
1879 int i, channel, slot, rank, lane;
1880 for (i = 0; i < 2; i++)
1881 for (slot = 0; slot < NUM_SLOTS; slot++)
1882 for (rank = 0; rank < NUM_RANKS; rank++)
1883 for (lane = 0; lane < 9; lane++)
1884 info->training.
1885 lane_timings[0][i][slot][rank][lane]
1886 = 32;
1887
1888 for (i = 1; i < 4; i++)
1889 for (channel = 0; channel < NUM_CHANNELS; channel++)
1890 for (slot = 0; slot < NUM_SLOTS; slot++)
1891 for (rank = 0; rank < NUM_RANKS; rank++)
1892 for (lane = 0; lane < 9; lane++) {
1893 info->training.
1894 lane_timings[i][channel]
1895 [slot][rank][lane] =
1896 read_500(info, channel,
1897 get_timing_register_addr
1898 (lane, i, slot,
1899 rank), 9)
1900 + (i == 1) * 11; // !!!!
1901 }
1902
1903}
1904
1905static u32 get_etalon2(int flip, u32 addr)
1906{
1907 const u16 invmask[] = {
1908 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1909 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1910 };
1911 u32 ret;
1912 u32 comp4 = addr / 480;
1913 addr %= 480;
1914 u32 comp1 = addr & 0xf;
1915 u32 comp2 = (addr >> 4) & 1;
1916 u32 comp3 = addr >> 5;
1917
1918 if (comp4)
1919 ret = 0x1010101 << (comp4 - 1);
1920 else
1921 ret = 0;
1922 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1923 ret = ~ret;
1924
1925 return ret;
1926}
1927
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001928static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001929{
1930 msr_t msr = {.lo = 0, .hi = 0 };
1931
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001932 wrmsr(MTRR_PHYS_BASE(3), msr);
1933 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001934}
1935
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001936static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001937{
1938 msr_t msr;
1939 msr.lo = base | MTRR_TYPE_WRPROT;
1940 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001941 wrmsr(MTRR_PHYS_BASE(3), msr);
1942 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001943 & 0xffffffff);
1944 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001945 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001946}
1947
1948static void flush_cache(u32 start, u32 size)
1949{
1950 u32 end;
1951 u32 addr;
1952
1953 end = start + (ALIGN_DOWN(size + 4096, 4096));
1954 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001955 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001956}
1957
1958static void clear_errors(void)
1959{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001960 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001961}
1962
1963static void write_testing(struct raminfo *info, int totalrank, int flip)
1964{
1965 int nwrites = 0;
1966 /* in 8-byte units. */
1967 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001968 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969
Patrick Rudolph819c2062019-11-29 19:27:37 +01001970 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001971 for (offset = 0; offset < 9 * 480; offset += 2) {
1972 write32(base + offset * 8, get_etalon2(flip, offset));
1973 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1974 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1975 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1976 nwrites += 4;
1977 if (nwrites >= 320) {
1978 clear_errors();
1979 nwrites = 0;
1980 }
1981 }
1982}
1983
1984static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1985{
1986 u8 failmask = 0;
1987 int i;
1988 int comp1, comp2, comp3;
1989 u32 failxor[2] = { 0, 0 };
1990
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001991 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001992
1993 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1994 for (comp1 = 0; comp1 < 4; comp1++)
1995 for (comp2 = 0; comp2 < 60; comp2++) {
1996 u32 re[4];
1997 u32 curroffset =
1998 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1999 read128((total_rank << 28) | (curroffset << 3),
2000 (u64 *) re);
2001 failxor[0] |=
2002 get_etalon2(flip, curroffset) ^ re[0];
2003 failxor[1] |=
2004 get_etalon2(flip, curroffset) ^ re[1];
2005 failxor[0] |=
2006 get_etalon2(flip, curroffset | 1) ^ re[2];
2007 failxor[1] |=
2008 get_etalon2(flip, curroffset | 1) ^ re[3];
2009 }
2010 for (i = 0; i < 8; i++)
2011 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2012 failmask |= 1 << i;
2013 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002014 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002015 flush_cache((total_rank << 28), 1728 * 5 * 4);
2016 return failmask;
2017}
2018
2019const u32 seed1[0x18] = {
2020 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2021 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2022 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2023 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2024 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2025 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2026};
2027
2028static u32 get_seed2(int a, int b)
2029{
2030 const u32 seed2[5] = {
2031 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2032 0x5b6db6db,
2033 };
2034 u32 r;
2035 r = seed2[(a + (a >= 10)) / 5];
2036 return b ? ~r : r;
2037}
2038
2039static int make_shift(int comp2, int comp5, int x)
2040{
2041 const u8 seed3[32] = {
2042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2043 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2044 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2045 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2046 };
2047
2048 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2049}
2050
2051static u32 get_etalon(int flip, u32 addr)
2052{
2053 u32 mask_byte = 0;
2054 int comp1 = (addr >> 1) & 1;
2055 int comp2 = (addr >> 3) & 0x1f;
2056 int comp3 = (addr >> 8) & 0xf;
2057 int comp4 = (addr >> 12) & 0xf;
2058 int comp5 = (addr >> 16) & 0x1f;
2059 u32 mask_bit = ~(0x10001 << comp3);
2060 u32 part1;
2061 u32 part2;
2062 int byte;
2063
2064 part2 =
2065 ((seed1[comp5] >>
2066 make_shift(comp2, comp5,
2067 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2068 part1 =
2069 ((seed1[comp5] >>
2070 make_shift(comp2, comp5,
2071 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2072
2073 for (byte = 0; byte < 4; byte++)
2074 if ((get_seed2(comp5, comp4) >>
2075 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2076 mask_byte |= 0xff << (8 * byte);
2077
2078 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2079 (comp3 + 16));
2080}
2081
2082static void
2083write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2084 char flip)
2085{
2086 int i;
2087 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002088 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2089 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002090}
2091
2092static u8
2093check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2094 char flip)
2095{
2096 u8 failmask = 0;
2097 u32 failxor[2];
2098 int i;
2099 int comp1, comp2, comp3;
2100
2101 failxor[0] = 0;
2102 failxor[1] = 0;
2103
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002104 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002105 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2106 for (comp1 = 0; comp1 < 16; comp1++)
2107 for (comp2 = 0; comp2 < 64; comp2++) {
2108 u32 addr =
2109 (totalrank << 28) | (region << 25) | (block
2110 << 16)
2111 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2112 2);
2113 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002114 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002115 }
2116 for (i = 0; i < 8; i++)
2117 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2118 failmask |= 1 << i;
2119 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002120 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002121 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2122 return failmask;
2123}
2124
2125static int check_bounded(unsigned short *vals, u16 bound)
2126{
2127 int i;
2128
2129 for (i = 0; i < 8; i++)
2130 if (vals[i] < bound)
2131 return 0;
2132 return 1;
2133}
2134
2135enum state {
2136 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2137};
2138
2139static int validate_state(enum state *in)
2140{
2141 int i;
2142 for (i = 0; i < 8; i++)
2143 if (in[i] != COMPLETE)
2144 return 0;
2145 return 1;
2146}
2147
2148static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002149do_fsm(enum state *state, u16 *counter,
2150 u8 fail_mask, int margin, int uplimit,
2151 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002152{
2153 int lane;
2154
2155 for (lane = 0; lane < 8; lane++) {
2156 int is_fail = (fail_mask >> lane) & 1;
2157 switch (state[lane]) {
2158 case BEFORE_USABLE:
2159 if (!is_fail) {
2160 counter[lane] = 1;
2161 state[lane] = AT_USABLE;
2162 break;
2163 }
2164 counter[lane] = 0;
2165 state[lane] = BEFORE_USABLE;
2166 break;
2167 case AT_USABLE:
2168 if (!is_fail) {
2169 ++counter[lane];
2170 if (counter[lane] >= margin) {
2171 state[lane] = AT_MARGIN;
2172 res_low[lane] = val - margin + 1;
2173 break;
2174 }
2175 state[lane] = 1;
2176 break;
2177 }
2178 counter[lane] = 0;
2179 state[lane] = BEFORE_USABLE;
2180 break;
2181 case AT_MARGIN:
2182 if (is_fail) {
2183 state[lane] = COMPLETE;
2184 res_high[lane] = val - 1;
2185 } else {
2186 counter[lane]++;
2187 state[lane] = AT_MARGIN;
2188 if (val == uplimit) {
2189 state[lane] = COMPLETE;
2190 res_high[lane] = uplimit;
2191 }
2192 }
2193 break;
2194 case COMPLETE:
2195 break;
2196 }
2197 }
2198}
2199
2200static void
2201train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2202 u8 total_rank, u8 reg_178, int first_run, int niter,
2203 timing_bounds_t * timings)
2204{
2205 int lane;
2206 enum state state[8];
2207 u16 count[8];
2208 u8 lower_usable[8];
2209 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002210 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002211 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002212 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002213
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002214 for (i = 0; i < 8; i++)
2215 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002216
2217 if (!first_run) {
2218 int is_all_ok = 1;
2219 for (lane = 0; lane < 8; lane++)
2220 if (timings[reg_178][channel][slot][rank][lane].
2221 smallest ==
2222 timings[reg_178][channel][slot][rank][lane].
2223 largest) {
2224 timings[reg_178][channel][slot][rank][lane].
2225 smallest = 0;
2226 timings[reg_178][channel][slot][rank][lane].
2227 largest = 0;
2228 is_all_ok = 0;
2229 }
2230 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002231 for (i = 0; i < 8; i++)
2232 state[i] = COMPLETE;
2233 }
2234 }
2235
2236 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2237 u8 failmask = 0;
2238 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2239 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2240 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002241 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002242 do_fsm(state, count, failmask, 5, 47, lower_usable,
2243 upper_usable, reg1b3);
2244 }
2245
2246 if (reg1b3) {
2247 write_1d0(0, 0x1b3, 6, 1);
2248 write_1d0(0, 0x1a3, 6, 1);
2249 for (lane = 0; lane < 8; lane++) {
2250 if (state[lane] == COMPLETE) {
2251 timings[reg_178][channel][slot][rank][lane].
2252 smallest =
2253 lower_usable[lane] +
2254 (info->training.
2255 lane_timings[0][channel][slot][rank][lane]
2256 & 0x3F) - 32;
2257 timings[reg_178][channel][slot][rank][lane].
2258 largest =
2259 upper_usable[lane] +
2260 (info->training.
2261 lane_timings[0][channel][slot][rank][lane]
2262 & 0x3F) - 32;
2263 }
2264 }
2265 }
2266
2267 if (!first_run) {
2268 for (lane = 0; lane < 8; lane++)
2269 if (state[lane] == COMPLETE) {
2270 write_500(info, channel,
2271 timings[reg_178][channel][slot][rank]
2272 [lane].smallest,
2273 get_timing_register_addr(lane, 0,
2274 slot, rank),
2275 9, 1);
2276 write_500(info, channel,
2277 timings[reg_178][channel][slot][rank]
2278 [lane].smallest +
2279 info->training.
2280 lane_timings[1][channel][slot][rank]
2281 [lane]
2282 -
2283 info->training.
2284 lane_timings[0][channel][slot][rank]
2285 [lane], get_timing_register_addr(lane,
2286 1,
2287 slot,
2288 rank),
2289 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002290 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002291 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002292 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002293
2294 do {
2295 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296 for (i = 0; i < niter; i++) {
2297 if (failmask == 0xFF)
2298 break;
2299 failmask |=
2300 check_testing_type2(info, total_rank, 2, i,
2301 0);
2302 failmask |=
2303 check_testing_type2(info, total_rank, 3, i,
2304 1);
2305 }
Felix Held04be2dd2018-07-29 04:53:22 +02002306 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002307 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002308 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002309 if ((1 << lane) & failmask) {
2310 if (timings[reg_178][channel]
2311 [slot][rank][lane].
2312 largest <=
2313 timings[reg_178][channel]
2314 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002315 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002316 [lane] = -1;
2317 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002318 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002319 [lane] = 0;
2320 timings[reg_178]
2321 [channel][slot]
2322 [rank][lane].
2323 smallest++;
2324 write_500(info, channel,
2325 timings
2326 [reg_178]
2327 [channel]
2328 [slot][rank]
2329 [lane].
2330 smallest,
2331 get_timing_register_addr
2332 (lane, 0,
2333 slot, rank),
2334 9, 1);
2335 write_500(info, channel,
2336 timings
2337 [reg_178]
2338 [channel]
2339 [slot][rank]
2340 [lane].
2341 smallest +
2342 info->
2343 training.
2344 lane_timings
2345 [1][channel]
2346 [slot][rank]
2347 [lane]
2348 -
2349 info->
2350 training.
2351 lane_timings
2352 [0][channel]
2353 [slot][rank]
2354 [lane],
2355 get_timing_register_addr
2356 (lane, 1,
2357 slot, rank),
2358 9, 1);
2359 }
2360 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002361 num_successfully_checked[lane]
2362 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363 }
2364 }
Felix Held04be2dd2018-07-29 04:53:22 +02002365 while (!check_bounded(num_successfully_checked, 2))
2366 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002367
2368 for (lane = 0; lane < 8; lane++)
2369 if (state[lane] == COMPLETE) {
2370 write_500(info, channel,
2371 timings[reg_178][channel][slot][rank]
2372 [lane].largest,
2373 get_timing_register_addr(lane, 0,
2374 slot, rank),
2375 9, 1);
2376 write_500(info, channel,
2377 timings[reg_178][channel][slot][rank]
2378 [lane].largest +
2379 info->training.
2380 lane_timings[1][channel][slot][rank]
2381 [lane]
2382 -
2383 info->training.
2384 lane_timings[0][channel][slot][rank]
2385 [lane], get_timing_register_addr(lane,
2386 1,
2387 slot,
2388 rank),
2389 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002390 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002391 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002392 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002393
2394 do {
2395 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002396 for (i = 0; i < niter; i++) {
2397 if (failmask == 0xFF)
2398 break;
2399 failmask |=
2400 check_testing_type2(info, total_rank, 2, i,
2401 0);
2402 failmask |=
2403 check_testing_type2(info, total_rank, 3, i,
2404 1);
2405 }
2406
Felix Held04be2dd2018-07-29 04:53:22 +02002407 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002408 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002409 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002410 if ((1 << lane) & failmask) {
2411 if (timings[reg_178][channel]
2412 [slot][rank][lane].
2413 largest <=
2414 timings[reg_178][channel]
2415 [slot][rank][lane].
2416 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002417 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002418 [lane] = -1;
2419 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002420 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 [lane] = 0;
2422 timings[reg_178]
2423 [channel][slot]
2424 [rank][lane].
2425 largest--;
2426 write_500(info, channel,
2427 timings
2428 [reg_178]
2429 [channel]
2430 [slot][rank]
2431 [lane].
2432 largest,
2433 get_timing_register_addr
2434 (lane, 0,
2435 slot, rank),
2436 9, 1);
2437 write_500(info, channel,
2438 timings
2439 [reg_178]
2440 [channel]
2441 [slot][rank]
2442 [lane].
2443 largest +
2444 info->
2445 training.
2446 lane_timings
2447 [1][channel]
2448 [slot][rank]
2449 [lane]
2450 -
2451 info->
2452 training.
2453 lane_timings
2454 [0][channel]
2455 [slot][rank]
2456 [lane],
2457 get_timing_register_addr
2458 (lane, 1,
2459 slot, rank),
2460 9, 1);
2461 }
2462 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002463 num_successfully_checked[lane]
2464 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002465 }
2466 }
2467 }
Felix Held04be2dd2018-07-29 04:53:22 +02002468 while (!check_bounded(num_successfully_checked, 3))
2469 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002470
2471 for (lane = 0; lane < 8; lane++) {
2472 write_500(info, channel,
2473 info->training.
2474 lane_timings[0][channel][slot][rank][lane],
2475 get_timing_register_addr(lane, 0, slot, rank),
2476 9, 1);
2477 write_500(info, channel,
2478 info->training.
2479 lane_timings[1][channel][slot][rank][lane],
2480 get_timing_register_addr(lane, 1, slot, rank),
2481 9, 1);
2482 if (timings[reg_178][channel][slot][rank][lane].
2483 largest <=
2484 timings[reg_178][channel][slot][rank][lane].
2485 smallest) {
2486 timings[reg_178][channel][slot][rank][lane].
2487 largest = 0;
2488 timings[reg_178][channel][slot][rank][lane].
2489 smallest = 0;
2490 }
2491 }
2492 }
2493}
2494
2495static void set_10b(struct raminfo *info, u8 val)
2496{
2497 int channel;
2498 int slot, rank;
2499 int lane;
2500
2501 if (read_1d0(0x10b, 6) == val)
2502 return;
2503
2504 write_1d0(val, 0x10b, 6, 1);
2505
2506 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2507 u16 reg_500;
2508 reg_500 = read_500(info, channel,
2509 get_timing_register_addr(lane, 0, slot,
2510 rank), 9);
2511 if (val == 1) {
2512 if (lut16[info->clock_speed_index] <= reg_500)
2513 reg_500 -= lut16[info->clock_speed_index];
2514 else
2515 reg_500 = 0;
2516 } else {
2517 reg_500 += lut16[info->clock_speed_index];
2518 }
2519 write_500(info, channel, reg_500,
2520 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2521 }
2522}
2523
2524static void set_ecc(int onoff)
2525{
2526 int channel;
2527 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2528 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002529 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002530 if (onoff)
2531 t |= 1;
2532 else
2533 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002534 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002535 }
2536}
2537
2538static void set_178(u8 val)
2539{
2540 if (val >= 31)
2541 val = val - 31;
2542 else
2543 val = 63 - val;
2544
2545 write_1d0(2 * val, 0x178, 7, 1);
2546}
2547
2548static void
2549write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2550 int type)
2551{
2552 int lane;
2553
2554 for (lane = 0; lane < 8; lane++)
2555 write_500(info, channel,
2556 info->training.
2557 lane_timings[type][channel][slot][rank][lane],
2558 get_timing_register_addr(lane, type, slot, rank), 9,
2559 0);
2560}
2561
2562static void
2563try_timing_offsets(struct raminfo *info, int channel,
2564 int slot, int rank, int totalrank)
2565{
2566 u16 count[8];
2567 enum state state[8];
2568 u8 lower_usable[8], upper_usable[8];
2569 int lane;
2570 int i;
2571 int flip = 1;
2572 int timing_offset;
2573
2574 for (i = 0; i < 8; i++)
2575 state[i] = BEFORE_USABLE;
2576
2577 memset(count, 0, sizeof(count));
2578
2579 for (lane = 0; lane < 8; lane++)
2580 write_500(info, channel,
2581 info->training.
2582 lane_timings[2][channel][slot][rank][lane] + 32,
2583 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2584
2585 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2586 timing_offset++) {
2587 u8 failmask;
2588 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2589 failmask = 0;
2590 for (i = 0; i < 2 && failmask != 0xff; i++) {
2591 flip = !flip;
2592 write_testing(info, totalrank, flip);
2593 failmask |= check_testing(info, totalrank, flip);
2594 }
2595 do_fsm(state, count, failmask, 10, 63, lower_usable,
2596 upper_usable, timing_offset);
2597 }
2598 write_1d0(0, 0x1bb, 6, 1);
2599 dump_timings(info);
2600 if (!validate_state(state))
2601 die("Couldn't discover DRAM timings (1)\n");
2602
2603 for (lane = 0; lane < 8; lane++) {
2604 u8 bias = 0;
2605
2606 if (info->silicon_revision) {
2607 int usable_length;
2608
2609 usable_length = upper_usable[lane] - lower_usable[lane];
2610 if (usable_length >= 20) {
2611 bias = usable_length / 2 - 10;
2612 if (bias >= 2)
2613 bias = 2;
2614 }
2615 }
2616 write_500(info, channel,
2617 info->training.
2618 lane_timings[2][channel][slot][rank][lane] +
2619 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2620 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2621 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2622 info->training.lane_timings[2][channel][slot][rank][lane] +
2623 lower_usable[lane];
2624 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2625 info->training.lane_timings[2][channel][slot][rank][lane] +
2626 upper_usable[lane];
2627 info->training.timing2_offset[channel][slot][rank][lane] =
2628 info->training.lane_timings[2][channel][slot][rank][lane];
2629 }
2630}
2631
2632static u8
2633choose_training(struct raminfo *info, int channel, int slot, int rank,
2634 int lane, timing_bounds_t * timings, u8 center_178)
2635{
2636 u16 central_weight;
2637 u16 side_weight;
2638 unsigned int sum = 0, count = 0;
2639 u8 span;
2640 u8 lower_margin, upper_margin;
2641 u8 reg_178;
2642 u8 result;
2643
2644 span = 12;
2645 central_weight = 20;
2646 side_weight = 20;
2647 if (info->silicon_revision == 1 && channel == 1) {
2648 central_weight = 5;
2649 side_weight = 20;
2650 if ((info->
2651 populated_ranks_mask[1] ^ (info->
2652 populated_ranks_mask[1] >> 2)) &
2653 1)
2654 span = 18;
2655 }
2656 if ((info->populated_ranks_mask[0] & 5) == 5) {
2657 central_weight = 20;
2658 side_weight = 20;
2659 }
2660 if (info->clock_speed_index >= 2
2661 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2662 if (info->silicon_revision == 1) {
2663 switch (channel) {
2664 case 0:
2665 if (lane == 1) {
2666 central_weight = 10;
2667 side_weight = 20;
2668 }
2669 break;
2670 case 1:
2671 if (lane == 6) {
2672 side_weight = 5;
2673 central_weight = 20;
2674 }
2675 break;
2676 }
2677 }
2678 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2679 side_weight = 5;
2680 central_weight = 20;
2681 }
2682 }
2683 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2684 reg_178 += span) {
2685 u8 smallest;
2686 u8 largest;
2687 largest = timings[reg_178][channel][slot][rank][lane].largest;
2688 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2689 if (largest - smallest + 1 >= 5) {
2690 unsigned int weight;
2691 if (reg_178 == center_178)
2692 weight = central_weight;
2693 else
2694 weight = side_weight;
2695 sum += weight * (largest + smallest);
2696 count += weight;
2697 }
2698 }
2699 dump_timings(info);
2700 if (count == 0)
2701 die("Couldn't discover DRAM timings (2)\n");
2702 result = sum / (2 * count);
2703 lower_margin =
2704 result - timings[center_178][channel][slot][rank][lane].smallest;
2705 upper_margin =
2706 timings[center_178][channel][slot][rank][lane].largest - result;
2707 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002708 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002709 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002710 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002711 return result;
2712}
2713
2714#define STANDARD_MIN_MARGIN 5
2715
2716static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2717{
2718 u16 margin[64];
2719 int lane, rank, slot, channel;
2720 u8 reg178;
2721 int count = 0, sum = 0;
2722
2723 for (reg178 = reg178_min[info->clock_speed_index];
2724 reg178 < reg178_max[info->clock_speed_index];
2725 reg178 += reg178_step[info->clock_speed_index]) {
2726 margin[reg178] = -1;
2727 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2728 int curmargin =
2729 timings[reg178][channel][slot][rank][lane].largest -
2730 timings[reg178][channel][slot][rank][lane].
2731 smallest + 1;
2732 if (curmargin < margin[reg178])
2733 margin[reg178] = curmargin;
2734 }
2735 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2736 u16 weight;
2737 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2738 sum += weight * reg178;
2739 count += weight;
2740 }
2741 }
2742 dump_timings(info);
2743 if (count == 0)
2744 die("Couldn't discover DRAM timings (3)\n");
2745
2746 u8 threshold;
2747
2748 for (threshold = 30; threshold >= 5; threshold--) {
2749 int usable_length = 0;
2750 int smallest_fount = 0;
2751 for (reg178 = reg178_min[info->clock_speed_index];
2752 reg178 < reg178_max[info->clock_speed_index];
2753 reg178 += reg178_step[info->clock_speed_index])
2754 if (margin[reg178] >= threshold) {
2755 usable_length +=
2756 reg178_step[info->clock_speed_index];
2757 info->training.reg178_largest =
2758 reg178 -
2759 2 * reg178_step[info->clock_speed_index];
2760
2761 if (!smallest_fount) {
2762 smallest_fount = 1;
2763 info->training.reg178_smallest =
2764 reg178 +
2765 reg178_step[info->
2766 clock_speed_index];
2767 }
2768 }
2769 if (usable_length >= 0x21)
2770 break;
2771 }
2772
2773 return sum / count;
2774}
2775
2776static int check_cached_sanity(struct raminfo *info)
2777{
2778 int lane;
2779 int slot, rank;
2780 int channel;
2781
2782 if (!info->cached_training)
2783 return 0;
2784
2785 for (channel = 0; channel < NUM_CHANNELS; channel++)
2786 for (slot = 0; slot < NUM_SLOTS; slot++)
2787 for (rank = 0; rank < NUM_RANKS; rank++)
2788 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2789 u16 cached_value, estimation_value;
2790 cached_value =
2791 info->cached_training->
2792 lane_timings[1][channel][slot][rank]
2793 [lane];
2794 if (cached_value >= 0x18
2795 && cached_value <= 0x1E7) {
2796 estimation_value =
2797 info->training.
2798 lane_timings[1][channel]
2799 [slot][rank][lane];
2800 if (estimation_value <
2801 cached_value - 24)
2802 return 0;
2803 if (estimation_value >
2804 cached_value + 24)
2805 return 0;
2806 }
2807 }
2808 return 1;
2809}
2810
2811static int try_cached_training(struct raminfo *info)
2812{
2813 u8 saved_243[2];
2814 u8 tm;
2815
2816 int channel, slot, rank, lane;
2817 int flip = 1;
2818 int i, j;
2819
2820 if (!check_cached_sanity(info))
2821 return 0;
2822
2823 info->training.reg178_center = info->cached_training->reg178_center;
2824 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2825 info->training.reg178_largest = info->cached_training->reg178_largest;
2826 memcpy(&info->training.timing_bounds,
2827 &info->cached_training->timing_bounds,
2828 sizeof(info->training.timing_bounds));
2829 memcpy(&info->training.timing_offset,
2830 &info->cached_training->timing_offset,
2831 sizeof(info->training.timing_offset));
2832
2833 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002834 saved_243[0] = MCHBAR8(0x243);
2835 saved_243[1] = MCHBAR8(0x643);
2836 MCHBAR8(0x243) = saved_243[0] | 2;
2837 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002838 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002839 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002840 if (read_1d0(0x10b, 6) & 1)
2841 set_10b(info, 0);
2842 for (tm = 0; tm < 2; tm++) {
2843 int totalrank;
2844
2845 set_178(tm ? info->cached_training->reg178_largest : info->
2846 cached_training->reg178_smallest);
2847
2848 totalrank = 0;
2849 /* Check timing ranges. With i == 0 we check smallest one and with
2850 i == 1 the largest bound. With j == 0 we check that on the bound
2851 it still works whereas with j == 1 we check that just outside of
2852 bound we fail.
2853 */
2854 FOR_POPULATED_RANKS_BACKWARDS {
2855 for (i = 0; i < 2; i++) {
2856 for (lane = 0; lane < 8; lane++) {
2857 write_500(info, channel,
2858 info->cached_training->
2859 timing2_bounds[channel][slot]
2860 [rank][lane][i],
2861 get_timing_register_addr(lane,
2862 3,
2863 slot,
2864 rank),
2865 9, 1);
2866
2867 if (!i)
2868 write_500(info, channel,
2869 info->
2870 cached_training->
2871 timing2_offset
2872 [channel][slot][rank]
2873 [lane],
2874 get_timing_register_addr
2875 (lane, 2, slot, rank),
2876 9, 1);
2877 write_500(info, channel,
2878 i ? info->cached_training->
2879 timing_bounds[tm][channel]
2880 [slot][rank][lane].
2881 largest : info->
2882 cached_training->
2883 timing_bounds[tm][channel]
2884 [slot][rank][lane].smallest,
2885 get_timing_register_addr(lane,
2886 0,
2887 slot,
2888 rank),
2889 9, 1);
2890 write_500(info, channel,
2891 info->cached_training->
2892 timing_offset[channel][slot]
2893 [rank][lane] +
2894 (i ? info->cached_training->
2895 timing_bounds[tm][channel]
2896 [slot][rank][lane].
2897 largest : info->
2898 cached_training->
2899 timing_bounds[tm][channel]
2900 [slot][rank][lane].
2901 smallest) - 64,
2902 get_timing_register_addr(lane,
2903 1,
2904 slot,
2905 rank),
2906 9, 1);
2907 }
2908 for (j = 0; j < 2; j++) {
2909 u8 failmask;
2910 u8 expected_failmask;
2911 char reg1b3;
2912
2913 reg1b3 = (j == 1) + 4;
2914 reg1b3 =
2915 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2916 write_1d0(reg1b3, 0x1bb, 6, 1);
2917 write_1d0(reg1b3, 0x1b3, 6, 1);
2918 write_1d0(reg1b3, 0x1a3, 6, 1);
2919
2920 flip = !flip;
2921 write_testing(info, totalrank, flip);
2922 failmask =
2923 check_testing(info, totalrank,
2924 flip);
2925 expected_failmask =
2926 j == 0 ? 0x00 : 0xff;
2927 if (failmask != expected_failmask)
2928 goto fail;
2929 }
2930 }
2931 totalrank++;
2932 }
2933 }
2934
2935 set_178(info->cached_training->reg178_center);
2936 if (info->use_ecc)
2937 set_ecc(1);
2938 write_training_data(info);
2939 write_1d0(0, 322, 3, 1);
2940 info->training = *info->cached_training;
2941
2942 write_1d0(0, 0x1bb, 6, 1);
2943 write_1d0(0, 0x1b3, 6, 1);
2944 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002945 MCHBAR8(0x243) = saved_243[0];
2946 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002947
2948 return 1;
2949
2950fail:
2951 FOR_POPULATED_RANKS {
2952 write_500_timings_type(info, channel, slot, rank, 1);
2953 write_500_timings_type(info, channel, slot, rank, 2);
2954 write_500_timings_type(info, channel, slot, rank, 3);
2955 }
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 0;
2964}
2965
2966static void do_ram_training(struct raminfo *info)
2967{
2968 u8 saved_243[2];
2969 int totalrank = 0;
2970 u8 reg_178;
2971 int niter;
2972
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002973 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002974 int lane, rank, slot, channel;
2975 u8 reg178_center;
2976
2977 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002978 saved_243[0] = MCHBAR8(0x243);
2979 saved_243[1] = MCHBAR8(0x643);
2980 MCHBAR8(0x243) = saved_243[0] | 2;
2981 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002982 switch (info->clock_speed_index) {
2983 case 0:
2984 niter = 5;
2985 break;
2986 case 1:
2987 niter = 10;
2988 break;
2989 default:
2990 niter = 19;
2991 break;
2992 }
2993 set_ecc(0);
2994
2995 FOR_POPULATED_RANKS_BACKWARDS {
2996 int i;
2997
2998 write_500_timings_type(info, channel, slot, rank, 0);
2999
3000 write_testing(info, totalrank, 0);
3001 for (i = 0; i < niter; i++) {
3002 write_testing_type2(info, totalrank, 2, i, 0);
3003 write_testing_type2(info, totalrank, 3, i, 1);
3004 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003005 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003006 totalrank++;
3007 }
3008
3009 if (reg178_min[info->clock_speed_index] <
3010 reg178_max[info->clock_speed_index])
3011 memset(timings[reg178_min[info->clock_speed_index]], 0,
3012 sizeof(timings[0]) *
3013 (reg178_max[info->clock_speed_index] -
3014 reg178_min[info->clock_speed_index]));
3015 for (reg_178 = reg178_min[info->clock_speed_index];
3016 reg_178 < reg178_max[info->clock_speed_index];
3017 reg_178 += reg178_step[info->clock_speed_index]) {
3018 totalrank = 0;
3019 set_178(reg_178);
3020 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3021 for (slot = 0; slot < NUM_SLOTS; slot++)
3022 for (rank = 0; rank < NUM_RANKS; rank++) {
3023 memset(&timings[reg_178][channel][slot]
3024 [rank][0].smallest, 0, 16);
3025 if (info->
3026 populated_ranks[channel][slot]
3027 [rank]) {
3028 train_ram_at_178(info, channel,
3029 slot, rank,
3030 totalrank,
3031 reg_178, 1,
3032 niter,
3033 timings);
3034 totalrank++;
3035 }
3036 }
3037 }
3038
3039 reg178_center = choose_reg178(info, timings);
3040
3041 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3042 info->training.timing_bounds[0][channel][slot][rank][lane].
3043 smallest =
3044 timings[info->training.
3045 reg178_smallest][channel][slot][rank][lane].
3046 smallest;
3047 info->training.timing_bounds[0][channel][slot][rank][lane].
3048 largest =
3049 timings[info->training.
3050 reg178_smallest][channel][slot][rank][lane].largest;
3051 info->training.timing_bounds[1][channel][slot][rank][lane].
3052 smallest =
3053 timings[info->training.
3054 reg178_largest][channel][slot][rank][lane].smallest;
3055 info->training.timing_bounds[1][channel][slot][rank][lane].
3056 largest =
3057 timings[info->training.
3058 reg178_largest][channel][slot][rank][lane].largest;
3059 info->training.timing_offset[channel][slot][rank][lane] =
3060 info->training.lane_timings[1][channel][slot][rank][lane]
3061 -
3062 info->training.lane_timings[0][channel][slot][rank][lane] +
3063 64;
3064 }
3065
3066 if (info->silicon_revision == 1
3067 && (info->
3068 populated_ranks_mask[1] ^ (info->
3069 populated_ranks_mask[1] >> 2)) & 1) {
3070 int ranks_after_channel1;
3071
3072 totalrank = 0;
3073 for (reg_178 = reg178_center - 18;
3074 reg_178 <= reg178_center + 18; reg_178 += 18) {
3075 totalrank = 0;
3076 set_178(reg_178);
3077 for (slot = 0; slot < NUM_SLOTS; slot++)
3078 for (rank = 0; rank < NUM_RANKS; rank++) {
3079 if (info->
3080 populated_ranks[1][slot][rank]) {
3081 train_ram_at_178(info, 1, slot,
3082 rank,
3083 totalrank,
3084 reg_178, 0,
3085 niter,
3086 timings);
3087 totalrank++;
3088 }
3089 }
3090 }
3091 ranks_after_channel1 = totalrank;
3092
3093 for (reg_178 = reg178_center - 12;
3094 reg_178 <= reg178_center + 12; reg_178 += 12) {
3095 totalrank = ranks_after_channel1;
3096 set_178(reg_178);
3097 for (slot = 0; slot < NUM_SLOTS; slot++)
3098 for (rank = 0; rank < NUM_RANKS; rank++)
3099 if (info->
3100 populated_ranks[0][slot][rank]) {
3101 train_ram_at_178(info, 0, slot,
3102 rank,
3103 totalrank,
3104 reg_178, 0,
3105 niter,
3106 timings);
3107 totalrank++;
3108 }
3109
3110 }
3111 } else {
3112 for (reg_178 = reg178_center - 12;
3113 reg_178 <= reg178_center + 12; reg_178 += 12) {
3114 totalrank = 0;
3115 set_178(reg_178);
3116 FOR_POPULATED_RANKS_BACKWARDS {
3117 train_ram_at_178(info, channel, slot, rank,
3118 totalrank, reg_178, 0, niter,
3119 timings);
3120 totalrank++;
3121 }
3122 }
3123 }
3124
3125 set_178(reg178_center);
3126 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3127 u16 tm0;
3128
3129 tm0 =
3130 choose_training(info, channel, slot, rank, lane, timings,
3131 reg178_center);
3132 write_500(info, channel, tm0,
3133 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3134 write_500(info, channel,
3135 tm0 +
3136 info->training.
3137 lane_timings[1][channel][slot][rank][lane] -
3138 info->training.
3139 lane_timings[0][channel][slot][rank][lane],
3140 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3141 }
3142
3143 totalrank = 0;
3144 FOR_POPULATED_RANKS_BACKWARDS {
3145 try_timing_offsets(info, channel, slot, rank, totalrank);
3146 totalrank++;
3147 }
Felix Held04be2dd2018-07-29 04:53:22 +02003148 MCHBAR8(0x243) = saved_243[0];
3149 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003150 write_1d0(0, 0x142, 3, 1);
3151 info->training.reg178_center = reg178_center;
3152}
3153
3154static void ram_training(struct raminfo *info)
3155{
3156 u16 saved_fc4;
3157
Felix Held04be2dd2018-07-29 04:53:22 +02003158 saved_fc4 = MCHBAR16(0xfc4);
3159 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003160
3161 if (info->revision >= 8)
3162 read_4090(info);
3163
3164 if (!try_cached_training(info))
3165 do_ram_training(info);
3166 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3167 && info->clock_speed_index < 2)
3168 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003169 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003170}
3171
Martin Roth468d02c2019-10-23 21:44:42 -06003172static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003173{
Martin Roth468d02c2019-10-23 21:44:42 -06003174 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003175 if (a > b) {
3176 t = a;
3177 a = b;
3178 b = t;
3179 }
3180 /* invariant a < b. */
3181 while (a) {
3182 t = b % a;
3183 b = a;
3184 a = t;
3185 }
3186 return b;
3187}
3188
3189static inline int div_roundup(int a, int b)
3190{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003191 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003192}
3193
Martin Roth468d02c2019-10-23 21:44:42 -06003194static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195{
3196 return (a * b) / gcd(a, b);
3197}
3198
3199struct stru1 {
3200 u8 freqs_reversed;
3201 u8 freq_diff_reduced;
3202 u8 freq_min_reduced;
3203 u8 divisor_f4_to_fmax;
3204 u8 divisor_f3_to_fmax;
3205 u8 freq4_to_max_remainder;
3206 u8 freq3_to_2_remainder;
3207 u8 freq3_to_2_remaindera;
3208 u8 freq4_to_2_remainder;
3209 int divisor_f3_to_f1, divisor_f4_to_f2;
3210 int common_time_unit_ps;
3211 int freq_max_reduced;
3212};
3213
3214static void
3215compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3216 int num_cycles_2, int num_cycles_1, int round_it,
3217 int add_freqs, struct stru1 *result)
3218{
3219 int g;
3220 int common_time_unit_ps;
3221 int freq1_reduced, freq2_reduced;
3222 int freq_min_reduced;
3223 int freq_max_reduced;
3224 int freq3, freq4;
3225
3226 g = gcd(freq1, freq2);
3227 freq1_reduced = freq1 / g;
3228 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003229 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3230 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003231
3232 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3233 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3234 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3235 if (add_freqs) {
3236 freq3 += freq2_reduced;
3237 freq4 += freq1_reduced;
3238 }
3239
3240 if (round_it) {
3241 result->freq3_to_2_remainder = 0;
3242 result->freq3_to_2_remaindera = 0;
3243 result->freq4_to_max_remainder = 0;
3244 result->divisor_f4_to_f2 = 0;
3245 result->divisor_f3_to_f1 = 0;
3246 } else {
3247 if (freq2_reduced < freq1_reduced) {
3248 result->freq3_to_2_remainder =
3249 result->freq3_to_2_remaindera =
3250 freq3 % freq1_reduced - freq1_reduced + 1;
3251 result->freq4_to_max_remainder =
3252 -(freq4 % freq1_reduced);
3253 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3254 result->divisor_f4_to_f2 =
3255 (freq4 -
3256 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3257 result->freq4_to_2_remainder =
3258 -(char)((freq1_reduced - freq2_reduced) +
3259 ((u8) freq4 -
3260 (freq1_reduced -
3261 freq2_reduced)) % (u8) freq2_reduced);
3262 } else {
3263 if (freq2_reduced > freq1_reduced) {
3264 result->freq4_to_max_remainder =
3265 (freq4 % freq2_reduced) - freq2_reduced + 1;
3266 result->freq4_to_2_remainder =
3267 freq4 % freq_max_reduced -
3268 freq_max_reduced + 1;
3269 } else {
3270 result->freq4_to_max_remainder =
3271 -(freq4 % freq2_reduced);
3272 result->freq4_to_2_remainder =
3273 -(char)(freq4 % freq_max_reduced);
3274 }
3275 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3276 result->divisor_f3_to_f1 =
3277 (freq3 -
3278 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3279 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3280 result->freq3_to_2_remaindera =
3281 -(char)((freq_max_reduced - freq_min_reduced) +
3282 (freq3 -
3283 (freq_max_reduced -
3284 freq_min_reduced)) % freq1_reduced);
3285 }
3286 }
3287 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3288 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3289 if (round_it) {
3290 if (freq2_reduced > freq1_reduced) {
3291 if (freq3 % freq_max_reduced)
3292 result->divisor_f3_to_fmax++;
3293 }
3294 if (freq2_reduced < freq1_reduced) {
3295 if (freq4 % freq_max_reduced)
3296 result->divisor_f4_to_fmax++;
3297 }
3298 }
3299 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3300 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3301 result->freq_min_reduced = freq_min_reduced;
3302 result->common_time_unit_ps = common_time_unit_ps;
3303 result->freq_max_reduced = freq_max_reduced;
3304}
3305
3306static void
3307set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3308 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3309 int num_cycles_4, int reverse)
3310{
3311 struct stru1 vv;
3312 char multiplier;
3313
3314 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3315 0, 1, &vv);
3316
3317 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003318 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003319 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3320 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3321 div_roundup(num_cycles_1,
3322 vv.common_time_unit_ps) +
3323 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3324 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3325
3326 u32 y =
3327 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3328 vv.freq_max_reduced * multiplier)
3329 | (vv.
3330 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3331 multiplier) << 16) | ((u8) (vv.
3332 freq_min_reduced
3333 *
3334 multiplier)
3335 << 24);
3336 u32 x =
3337 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3338 divisor_f3_to_f1
3339 << 16)
3340 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3341 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003342 MCHBAR32(reg) = y;
3343 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003344 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003345 MCHBAR32(reg + 4) = y;
3346 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003347 }
3348}
3349
3350static void
3351set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3352 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3353 int num_cycles_4)
3354{
3355 struct stru1 ratios1;
3356 struct stru1 ratios2;
3357
3358 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3359 0, 1, &ratios2);
3360 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3361 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003362 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003363 ratios1.freq4_to_max_remainder | (ratios2.
3364 freq4_to_max_remainder
3365 << 8)
3366 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3367 divisor_f4_to_fmax
3368 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003369 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3370 (ratios2.freq4_to_max_remainder << 8) |
3371 (ratios1.divisor_f4_to_fmax << 16) |
3372 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003373}
3374
3375static void
3376set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3377 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3378{
3379 struct stru1 ratios;
3380
3381 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3382 round_it, add_freqs, &ratios);
3383 switch (mode) {
3384 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003385 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3386 (ratios.freqs_reversed << 8);
3387 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3388 (ratios.freq4_to_max_remainder << 8) |
3389 (ratios.divisor_f3_to_fmax << 16) |
3390 (ratios.divisor_f4_to_fmax << 20) |
3391 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003392 break;
3393
3394 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003395 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3396 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003397 break;
3398
3399 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003400 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3401 (ratios.freq4_to_max_remainder << 8) |
3402 (ratios.divisor_f3_to_fmax << 16) |
3403 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003404 break;
3405
3406 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003407 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3408 (ratios.divisor_f4_to_fmax << 8) |
3409 (ratios.freqs_reversed << 12) |
3410 (ratios.freq_min_reduced << 16) |
3411 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003412 break;
3413 }
3414}
3415
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003416static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003417{
3418 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3419 0, 1);
3420 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3421 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3422 1);
3423 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3424 frequency_11(info), 1231, 1524, 0, 1);
3425 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3426 frequency_11(info) / 2, 1278, 2008, 0, 1);
3427 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3428 1167, 1539, 0, 1);
3429 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3430 frequency_11(info) / 2, 1403, 1318, 0, 1);
3431 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3432 1);
3433 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3434 1);
3435 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3436 1, 1);
3437 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3438 1);
3439 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3440 frequency_11(info) / 2, 4000, 0, 0, 0);
3441 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3442 frequency_11(info) / 2, 4000, 4000, 0, 0);
3443
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003444 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003445 printk(RAM_SPEW, "[6dc] <= %x\n",
3446 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003447 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003448 } else
3449 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3450 info->delay46_ps[0], 0,
3451 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003452 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3453 frequency_11(info), 2500, 0, 0, 0);
3454 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3455 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003456 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003457 printk(RAM_SPEW, "[6e8] <= %x\n",
3458 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003459 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003460 } else
3461 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3462 info->delay46_ps[1], 0,
3463 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003464 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3465 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3466 470, 0);
3467 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3468 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3469 454, 459, 0);
3470 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3471 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3472 2588, 0);
3473 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3474 2405, 0);
3475 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3476 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3477 480, 0);
3478 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003479 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3480 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003481}
3482
3483static u16 get_max_timing(struct raminfo *info, int channel)
3484{
3485 int slot, rank, lane;
3486 u16 ret = 0;
3487
Felix Held04be2dd2018-07-29 04:53:22 +02003488 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003489 return 384;
3490
3491 if (info->revision < 8)
3492 return 256;
3493
3494 for (slot = 0; slot < NUM_SLOTS; slot++)
3495 for (rank = 0; rank < NUM_RANKS; rank++)
3496 if (info->populated_ranks[channel][slot][rank])
3497 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003498 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003499 get_timing_register_addr
3500 (lane, 0, slot,
3501 rank), 9));
3502 return ret;
3503}
3504
3505static void set_274265(struct raminfo *info)
3506{
3507 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3508 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3509 int delay_e_over_cycle_ps;
3510 int cycletime_ps;
3511 int channel;
3512
3513 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003514 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003515 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3516 cycletime_ps =
3517 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3518 delay_d_ps =
3519 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3520 - info->some_delay_3_ps_rounded + 200;
3521 if (!
3522 ((info->silicon_revision == 0
3523 || info->silicon_revision == 1)
3524 && (info->revision >= 8)))
3525 delay_d_ps += halfcycle_ps(info) * 2;
3526 delay_d_ps +=
3527 halfcycle_ps(info) * (!info->revision_flag_1 +
3528 info->some_delay_2_halfcycles_ceil +
3529 2 * info->some_delay_1_cycle_floor +
3530 info->clock_speed_index +
3531 2 * info->cas_latency - 7 + 11);
3532 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3533
Felix Held04be2dd2018-07-29 04:53:22 +02003534 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3535 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3536 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003537 delay_d_ps += 650;
3538 delay_c_ps = delay_d_ps + 1800;
3539 if (delay_c_ps <= delay_a_ps)
3540 delay_e_ps = 0;
3541 else
3542 delay_e_ps =
3543 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3544 cycletime_ps);
3545
3546 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3547 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3548 delay_f_cycles =
3549 div_roundup(2500 - delay_e_over_cycle_ps,
3550 2 * halfcycle_ps(info));
3551 if (delay_f_cycles > delay_e_cycles) {
3552 info->delay46_ps[channel] = delay_e_ps;
3553 delay_e_cycles = 0;
3554 } else {
3555 info->delay46_ps[channel] =
3556 delay_e_over_cycle_ps +
3557 2 * halfcycle_ps(info) * delay_f_cycles;
3558 delay_e_cycles -= delay_f_cycles;
3559 }
3560
3561 if (info->delay46_ps[channel] < 2500) {
3562 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003563 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003564 }
3565 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3566 if (delay_b_ps <= delay_a_ps)
3567 delay_b_ps = 0;
3568 else
3569 delay_b_ps -= delay_a_ps;
3570 info->delay54_ps[channel] =
3571 cycletime_ps * div_roundup(delay_b_ps,
3572 cycletime_ps) -
3573 2 * halfcycle_ps(info) * delay_e_cycles;
3574 if (info->delay54_ps[channel] < 2500)
3575 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003576 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003577 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3578 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003579 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003580 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003581 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003582 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3583 4 * halfcycle_ps(info)) - 6;
3584 MCHBAR32((channel << 10) + 0x274) =
3585 info->training.reg274265[channel][1] |
3586 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003587 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003588 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3589 4 * halfcycle_ps(info)) + 1;
3590 MCHBAR16((channel << 10) + 0x265) =
3591 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003592 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003593 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003594 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 else
Felix Held04be2dd2018-07-29 04:53:22 +02003596 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003597}
3598
3599static void restore_274265(struct raminfo *info)
3600{
3601 int channel;
3602
3603 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003604 MCHBAR32((channel << 10) + 0x274) =
3605 (info->cached_training->reg274265[channel][0] << 16) |
3606 info->cached_training->reg274265[channel][1];
3607 MCHBAR16((channel << 10) + 0x265) =
3608 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003610 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003611 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612 else
Felix Held04be2dd2018-07-29 04:53:22 +02003613 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003614}
3615
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616static void dmi_setup(void)
3617{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003618 gav(DMIBAR8(0x254));
3619 DMIBAR8(0x254) = 0x1;
3620 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003621 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622
Angel Ponsd071c4d2020-09-14 23:51:35 +02003623 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624
3625 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3626 DEFAULT_GPIOBASE | 0x38);
3627 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3628}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003630void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003633 u16 ggc;
3634 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635
Felix Held04be2dd2018-07-29 04:53:22 +02003636 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3638 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003639 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003640 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003641 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642
3643 dmi_setup();
3644
Felix Held04be2dd2018-07-29 04:53:22 +02003645 MCHBAR16(0x1170) = 0xa880;
3646 MCHBAR8(0x11c1) = 0x1;
3647 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003648 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003650 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3651 /* 0 for 32MB */
3652 gfxsize = 0;
3653 }
3654
3655 ggc = 0xb00 | ((gfxsize + 5) << 4);
3656
Angel Pons16fe1e02020-07-22 16:12:33 +02003657 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003658
3659 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003660 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661
3662 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003663 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003664 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003665 MCHBAR16_OR(0x2c30, 0x200);
3666 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003667 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003668 pci_read_config8(GMA, MSAC); // = 0x2
3669 pci_write_config8(GMA, MSAC, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003670 read8(DEFAULT_RCBA + 0x2318);
3671 write8(DEFAULT_RCBA + 0x2318, 0x47);
3672 read8(DEFAULT_RCBA + 0x2320);
3673 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674 }
3675
Felix Heldf83d80b2018-07-29 05:30:30 +02003676 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677
Angel Pons16fe1e02020-07-22 16:12:33 +02003678 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003679 gav(read32(DEFAULT_RCBA + 0x3428));
3680 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003681}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003683void raminit(const int s3resume, const u8 *spd_addrmap)
3684{
Martin Roth468d02c2019-10-23 21:44:42 -06003685 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003686 int i;
3687 struct raminfo info;
3688 u8 x2ca8;
3689 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003690 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003691
Felix Held04be2dd2018-07-29 04:53:22 +02003692 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003693
3694 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3695
Angel Pons16fe1e02020-07-22 16:12:33 +02003696 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003697
3698 memset(&info, 0x5a, sizeof(info));
3699
3700 info.last_500_command[0] = 0;
3701 info.last_500_command[1] = 0;
3702
3703 info.fsb_frequency = 135 * 2;
3704 info.board_lane_delay[0] = 0x14;
3705 info.board_lane_delay[1] = 0x07;
3706 info.board_lane_delay[2] = 0x07;
3707 info.board_lane_delay[3] = 0x08;
3708 info.board_lane_delay[4] = 0x56;
3709 info.board_lane_delay[5] = 0x04;
3710 info.board_lane_delay[6] = 0x04;
3711 info.board_lane_delay[7] = 0x05;
3712 info.board_lane_delay[8] = 0x10;
3713
3714 info.training.reg_178 = 0;
3715 info.training.reg_10b = 0;
3716
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003717 info.memory_reserved_for_heci_mb = 0;
3718
3719 /* before SPD */
3720 timestamp_add_now(101);
3721
Felix Held29a9c072018-07-29 01:34:45 +02003722 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003723 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003724
3725 collect_system_info(&info);
3726
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3728
3729 info.use_ecc = 1;
3730 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003731 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003732 int v;
3733 int try;
3734 int addr;
3735 const u8 useful_addresses[] = {
3736 DEVICE_TYPE,
3737 MODULE_TYPE,
3738 DENSITY,
3739 RANKS_AND_DQ,
3740 MEMORY_BUS_WIDTH,
3741 TIMEBASE_DIVIDEND,
3742 TIMEBASE_DIVISOR,
3743 CYCLETIME,
3744 CAS_LATENCIES_LSB,
3745 CAS_LATENCIES_MSB,
3746 CAS_LATENCY_TIME,
3747 0x11, 0x12, 0x13, 0x14, 0x15,
3748 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3749 0x1c, 0x1d,
3750 THERMAL_AND_REFRESH,
3751 0x20,
3752 REFERENCE_RAW_CARD_USED,
3753 RANK1_ADDRESS_MAPPING,
3754 0x75, 0x76, 0x77, 0x78,
3755 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3756 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3757 0x85, 0x86, 0x87, 0x88,
3758 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3759 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3760 0x95
3761 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003762 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763 continue;
3764 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003765 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766 DEVICE_TYPE);
3767 if (v >= 0)
3768 break;
3769 }
3770 if (v < 0)
3771 continue;
3772 for (addr = 0;
3773 addr <
3774 sizeof(useful_addresses) /
3775 sizeof(useful_addresses[0]); addr++)
3776 gav(info.
3777 spd[channel][0][useful_addresses
3778 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003779 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003780 useful_addresses
3781 [addr]));
3782 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3783 die("Only DDR3 is supported");
3784
3785 v = info.spd[channel][0][RANKS_AND_DQ];
3786 info.populated_ranks[channel][0][0] = 1;
3787 info.populated_ranks[channel][0][1] =
3788 ((v >> 3) & 7);
3789 if (((v >> 3) & 7) > 1)
3790 die("At most 2 ranks are supported");
3791 if ((v & 7) == 0 || (v & 7) > 2)
3792 die("Only x8 and x16 modules are supported");
3793 if ((info.
3794 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3795 && (info.
3796 spd[channel][slot][MODULE_TYPE] & 0xF)
3797 != 3)
3798 die("Registered memory is not supported");
3799 info.is_x16_module[channel][0] = (v & 7) - 1;
3800 info.density[channel][slot] =
3801 info.spd[channel][slot][DENSITY] & 0xF;
3802 if (!
3803 (info.
3804 spd[channel][slot][MEMORY_BUS_WIDTH] &
3805 0x18))
3806 info.use_ecc = 0;
3807 }
3808
3809 gav(0x55);
3810
3811 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3812 int v = 0;
3813 for (slot = 0; slot < NUM_SLOTS; slot++)
3814 for (rank = 0; rank < NUM_RANKS; rank++)
3815 v |= info.
3816 populated_ranks[channel][slot][rank]
3817 << (2 * slot + rank);
3818 info.populated_ranks_mask[channel] = v;
3819 }
3820
3821 gav(0x55);
3822
Angel Pons16fe1e02020-07-22 16:12:33 +02003823 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003824 }
3825
3826 /* after SPD */
3827 timestamp_add_now(102);
3828
Felix Held04be2dd2018-07-29 04:53:22 +02003829 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003830
3831 collect_system_info(&info);
3832 calculate_timings(&info);
3833
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003834 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003835 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003836 if (x2ca8 == 0 && (reg8 & 0x80)) {
3837 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3838 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3839 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3840 */
3841
3842 /* Clear bit7. */
3843
3844 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3845 (reg8 & ~(1 << 7)));
3846
3847 printk(BIOS_INFO,
3848 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003849 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850 }
3851 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003852
3853 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003854 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3855 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003856
3857 compute_derived_timings(&info);
3858
3859 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003860 gav(MCHBAR8(0x164));
3861 MCHBAR8(0x164) = 0x26;
3862 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863 }
3864
Felix Held04be2dd2018-07-29 04:53:22 +02003865 MCHBAR32_OR(0x18b4, 0x210000);
3866 MCHBAR32_OR(0x1890, 0x2000000);
3867 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868
Angel Ponsa457e352020-07-22 18:17:33 +02003869 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3870 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
Felix Held04be2dd2018-07-29 04:53:22 +02003872 gav(MCHBAR16(0x2c10));
3873 MCHBAR16(0x2c10) = 0x412;
3874 gav(MCHBAR16(0x2c10));
3875 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876
Felix Held04be2dd2018-07-29 04:53:22 +02003877 gav(MCHBAR8(0x2ca8)); // !!!!
3878 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879
Angel Ponsa457e352020-07-22 18:17:33 +02003880 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3881 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003882 gav(MCHBAR32(0x1c04)); // !!!!
3883 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884
3885 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003886 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887 }
3888
Felix Held04be2dd2018-07-29 04:53:22 +02003889 MCHBAR32(0x18d8) = 0x120000;
3890 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003891 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3892 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003893 MCHBAR32(0x18d8) = 0x40000;
3894 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3896 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR32(0x18d8) = 0x180000;
3898 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003899 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3900 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003901 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003902
Felix Held04be2dd2018-07-29 04:53:22 +02003903 gav(MCHBAR32(0x18dc)); // !!!!
3904 MCHBAR32(0x18dc) = 0x3;
3905 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906
3907 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003908 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003909 }
3910
Felix Held04be2dd2018-07-29 04:53:22 +02003911 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003912 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003913 MCHBAR32(0x1a10) = 0x4200010e;
3914 MCHBAR32_OR(0x18b8, 0x200);
3915 gav(MCHBAR32(0x1918)); // !!!!
3916 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003917
Felix Held04be2dd2018-07-29 04:53:22 +02003918 gav(MCHBAR32(0x18b8)); // !!!!
3919 MCHBAR32(0x18b8) = 0xe00;
3920 gav(MCHBAR32(0x182c)); // !!!!
3921 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003922 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3923 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3925 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003926
Felix Held04be2dd2018-07-29 04:53:22 +02003927 MCHBAR32_AND(0x18b4, 0xffff7fff);
3928 gav(MCHBAR32(0x1a68)); // !!!!
3929 MCHBAR32(0x1a68) = 0x343800;
3930 gav(MCHBAR32(0x1e68)); // !!!!
3931 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003932
3933 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003934 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935 }
3936
Angel Pons08143572020-07-22 17:47:06 +02003937 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3938 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3939 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3940 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3941 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003942 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3943 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003944 gav(MCHBAR32(0x1af0)); // !!!!
3945 gav(MCHBAR32(0x1af0)); // !!!!
3946 MCHBAR32(0x1af0) = 0x1f020003;
3947 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003949 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
Felix Held04be2dd2018-07-29 04:53:22 +02003953 gav(MCHBAR32(0x1890)); // !!!!
3954 MCHBAR32(0x1890) = 0x80102;
3955 gav(MCHBAR32(0x18b4)); // !!!!
3956 MCHBAR32(0x18b4) = 0x216000;
3957 MCHBAR32(0x18a4) = 0x22222222;
3958 MCHBAR32(0x18a8) = 0x22222222;
3959 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003960
3961 udelay(1000);
3962
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003963 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003964
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003965 if (x2ca8 == 0) {
3966 int j;
3967 if (s3resume && info.cached_training) {
3968 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003969 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003970 info.cached_training->reg2ca9_bit0);
3971 for (i = 0; i < 2; i++)
3972 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003973 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003974 i, j, info.cached_training->reg274265[i][j]);
3975 } else {
3976 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003977 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003978 info.training.reg2ca9_bit0);
3979 for (i = 0; i < 2; i++)
3980 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003981 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003982 i, j, info.training.reg274265[i][j]);
3983 }
3984
3985 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003986
3987 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003988 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003989 }
3990
3991 udelay(1000);
3992
3993 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003994 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003995 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003996 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3997 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3998 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003999
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004000 MCHBAR8(0x1150);
4001 MCHBAR8(0x1151);
4002 MCHBAR8(0x1022);
4003 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004004 MCHBAR32(0x1300) = 0x60606060;
4005 MCHBAR32(0x1304) = 0x60606060;
4006 MCHBAR32(0x1308) = 0x78797a7b;
4007 MCHBAR32(0x130c) = 0x7c7d7e7f;
4008 MCHBAR32(0x1310) = 0x60606060;
4009 MCHBAR32(0x1314) = 0x60606060;
4010 MCHBAR32(0x1318) = 0x60606060;
4011 MCHBAR32(0x131c) = 0x60606060;
4012 MCHBAR32(0x1320) = 0x50515253;
4013 MCHBAR32(0x1324) = 0x54555657;
4014 MCHBAR32(0x1328) = 0x58595a5b;
4015 MCHBAR32(0x132c) = 0x5c5d5e5f;
4016 MCHBAR32(0x1330) = 0x40414243;
4017 MCHBAR32(0x1334) = 0x44454647;
4018 MCHBAR32(0x1338) = 0x48494a4b;
4019 MCHBAR32(0x133c) = 0x4c4d4e4f;
4020 MCHBAR32(0x1340) = 0x30313233;
4021 MCHBAR32(0x1344) = 0x34353637;
4022 MCHBAR32(0x1348) = 0x38393a3b;
4023 MCHBAR32(0x134c) = 0x3c3d3e3f;
4024 MCHBAR32(0x1350) = 0x20212223;
4025 MCHBAR32(0x1354) = 0x24252627;
4026 MCHBAR32(0x1358) = 0x28292a2b;
4027 MCHBAR32(0x135c) = 0x2c2d2e2f;
4028 MCHBAR32(0x1360) = 0x10111213;
4029 MCHBAR32(0x1364) = 0x14151617;
4030 MCHBAR32(0x1368) = 0x18191a1b;
4031 MCHBAR32(0x136c) = 0x1c1d1e1f;
4032 MCHBAR32(0x1370) = 0x10203;
4033 MCHBAR32(0x1374) = 0x4050607;
4034 MCHBAR32(0x1378) = 0x8090a0b;
4035 MCHBAR32(0x137c) = 0xc0d0e0f;
4036 MCHBAR8(0x11cc) = 0x4e;
4037 MCHBAR32(0x1110) = 0x73970404;
4038 MCHBAR32(0x1114) = 0x72960404;
4039 MCHBAR32(0x1118) = 0x6f950404;
4040 MCHBAR32(0x111c) = 0x6d940404;
4041 MCHBAR32(0x1120) = 0x6a930404;
4042 MCHBAR32(0x1124) = 0x68a41404;
4043 MCHBAR32(0x1128) = 0x66a21404;
4044 MCHBAR32(0x112c) = 0x63a01404;
4045 MCHBAR32(0x1130) = 0x609e1404;
4046 MCHBAR32(0x1134) = 0x5f9c1404;
4047 MCHBAR32(0x1138) = 0x5c961404;
4048 MCHBAR32(0x113c) = 0x58a02404;
4049 MCHBAR32(0x1140) = 0x54942404;
4050 MCHBAR32(0x1190) = 0x900080a;
4051 MCHBAR16(0x11c0) = 0xc40b;
4052 MCHBAR16(0x11c2) = 0x303;
4053 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004054 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004055 MCHBAR32(0x11b8) = 0x70c3000;
4056 MCHBAR8(0x11ec) = 0xa;
4057 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004058 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004059 MCHBAR16(0x11ca) = 0xfa;
4060 MCHBAR32(0x11e4) = 0x4e20;
4061 MCHBAR8(0x11bc) = 0xf;
4062 MCHBAR16(0x11da) = 0x19;
4063 MCHBAR16(0x11ba) = 0x470c;
4064 MCHBAR32(0x1680) = 0xe6ffe4ff;
4065 MCHBAR32(0x1684) = 0xdeffdaff;
4066 MCHBAR32(0x1688) = 0xd4ffd0ff;
4067 MCHBAR32(0x168c) = 0xccffc6ff;
4068 MCHBAR32(0x1690) = 0xc0ffbeff;
4069 MCHBAR32(0x1694) = 0xb8ffb0ff;
4070 MCHBAR32(0x1698) = 0xa8ff0000;
4071 MCHBAR32(0x169c) = 0xc00;
4072 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004073 }
4074
Felix Held04be2dd2018-07-29 04:53:22 +02004075 MCHBAR32(0x124c) = 0x15040d00;
4076 MCHBAR32(0x1250) = 0x7f0000;
4077 MCHBAR32(0x1254) = 0x1e220004;
4078 MCHBAR32(0x1258) = 0x4000004;
4079 MCHBAR32(0x1278) = 0x0;
4080 MCHBAR32(0x125c) = 0x0;
4081 MCHBAR32(0x1260) = 0x0;
4082 MCHBAR32(0x1264) = 0x0;
4083 MCHBAR32(0x1268) = 0x0;
4084 MCHBAR32(0x126c) = 0x0;
4085 MCHBAR32(0x1270) = 0x0;
4086 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004087 }
4088
4089 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004090 MCHBAR16(0x1214) = 0x320;
4091 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004092 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4093 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004094 MCHBAR32(0x1400) = 0x13040020;
4095 MCHBAR32(0x1404) = 0xe090120;
4096 MCHBAR32(0x1408) = 0x5120220;
4097 MCHBAR32(0x140c) = 0x5120330;
4098 MCHBAR32(0x1410) = 0xe090220;
4099 MCHBAR32(0x1414) = 0x1010001;
4100 MCHBAR32(0x1418) = 0x1110000;
4101 MCHBAR32(0x141c) = 0x9020020;
4102 MCHBAR32(0x1420) = 0xd090220;
4103 MCHBAR32(0x1424) = 0x2090220;
4104 MCHBAR32(0x1428) = 0x2090330;
4105 MCHBAR32(0x142c) = 0xd090220;
4106 MCHBAR32(0x1430) = 0x1010001;
4107 MCHBAR32(0x1434) = 0x1110000;
4108 MCHBAR32(0x1438) = 0x11040020;
4109 MCHBAR32(0x143c) = 0x4030220;
4110 MCHBAR32(0x1440) = 0x1060220;
4111 MCHBAR32(0x1444) = 0x1060330;
4112 MCHBAR32(0x1448) = 0x4030220;
4113 MCHBAR32(0x144c) = 0x1010001;
4114 MCHBAR32(0x1450) = 0x1110000;
4115 MCHBAR32(0x1454) = 0x4010020;
4116 MCHBAR32(0x1458) = 0xb090220;
4117 MCHBAR32(0x145c) = 0x1090220;
4118 MCHBAR32(0x1460) = 0x1090330;
4119 MCHBAR32(0x1464) = 0xb090220;
4120 MCHBAR32(0x1468) = 0x1010001;
4121 MCHBAR32(0x146c) = 0x1110000;
4122 MCHBAR32(0x1470) = 0xf040020;
4123 MCHBAR32(0x1474) = 0xa090220;
4124 MCHBAR32(0x1478) = 0x1120220;
4125 MCHBAR32(0x147c) = 0x1120330;
4126 MCHBAR32(0x1480) = 0xa090220;
4127 MCHBAR32(0x1484) = 0x1010001;
4128 MCHBAR32(0x1488) = 0x1110000;
4129 MCHBAR32(0x148c) = 0x7020020;
4130 MCHBAR32(0x1490) = 0x1010220;
4131 MCHBAR32(0x1494) = 0x10210;
4132 MCHBAR32(0x1498) = 0x10320;
4133 MCHBAR32(0x149c) = 0x1010220;
4134 MCHBAR32(0x14a0) = 0x1010001;
4135 MCHBAR32(0x14a4) = 0x1110000;
4136 MCHBAR32(0x14a8) = 0xd040020;
4137 MCHBAR32(0x14ac) = 0x8090220;
4138 MCHBAR32(0x14b0) = 0x1111310;
4139 MCHBAR32(0x14b4) = 0x1111420;
4140 MCHBAR32(0x14b8) = 0x8090220;
4141 MCHBAR32(0x14bc) = 0x1010001;
4142 MCHBAR32(0x14c0) = 0x1110000;
4143 MCHBAR32(0x14c4) = 0x3010020;
4144 MCHBAR32(0x14c8) = 0x7090220;
4145 MCHBAR32(0x14cc) = 0x1081310;
4146 MCHBAR32(0x14d0) = 0x1081420;
4147 MCHBAR32(0x14d4) = 0x7090220;
4148 MCHBAR32(0x14d8) = 0x1010001;
4149 MCHBAR32(0x14dc) = 0x1110000;
4150 MCHBAR32(0x14e0) = 0xb040020;
4151 MCHBAR32(0x14e4) = 0x2030220;
4152 MCHBAR32(0x14e8) = 0x1051310;
4153 MCHBAR32(0x14ec) = 0x1051420;
4154 MCHBAR32(0x14f0) = 0x2030220;
4155 MCHBAR32(0x14f4) = 0x1010001;
4156 MCHBAR32(0x14f8) = 0x1110000;
4157 MCHBAR32(0x14fc) = 0x5020020;
4158 MCHBAR32(0x1500) = 0x5090220;
4159 MCHBAR32(0x1504) = 0x2071310;
4160 MCHBAR32(0x1508) = 0x2071420;
4161 MCHBAR32(0x150c) = 0x5090220;
4162 MCHBAR32(0x1510) = 0x1010001;
4163 MCHBAR32(0x1514) = 0x1110000;
4164 MCHBAR32(0x1518) = 0x7040120;
4165 MCHBAR32(0x151c) = 0x2090220;
4166 MCHBAR32(0x1520) = 0x70b1210;
4167 MCHBAR32(0x1524) = 0x70b1310;
4168 MCHBAR32(0x1528) = 0x2090220;
4169 MCHBAR32(0x152c) = 0x1010001;
4170 MCHBAR32(0x1530) = 0x1110000;
4171 MCHBAR32(0x1534) = 0x1010110;
4172 MCHBAR32(0x1538) = 0x1081310;
4173 MCHBAR32(0x153c) = 0x5041200;
4174 MCHBAR32(0x1540) = 0x5041310;
4175 MCHBAR32(0x1544) = 0x1081310;
4176 MCHBAR32(0x1548) = 0x1010001;
4177 MCHBAR32(0x154c) = 0x1110000;
4178 MCHBAR32(0x1550) = 0x1040120;
4179 MCHBAR32(0x1554) = 0x4051210;
4180 MCHBAR32(0x1558) = 0xd051200;
4181 MCHBAR32(0x155c) = 0xd051200;
4182 MCHBAR32(0x1560) = 0x4051210;
4183 MCHBAR32(0x1564) = 0x1010001;
4184 MCHBAR32(0x1568) = 0x1110000;
4185 MCHBAR16(0x1222) = 0x220a;
4186 MCHBAR16(0x123c) = 0x1fc0;
4187 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004188 }
4189
Felix Heldf83d80b2018-07-29 05:30:30 +02004190 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004191 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004192 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004193
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004194 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004195
4196 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004197 MCHBAR8_AND(0x2ca8, ~3);
4198 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004199 /* This issues a CPU reset without resetting the platform */
4200 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004201 /* Write back the S3 state to PM1_CNT to let the reset CPU
4202 know it also needs to take the s3 path. */
4203 if (s3resume)
4204 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4205 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004206 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004207 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004208 }
4209
Felix Held04be2dd2018-07-29 04:53:22 +02004210 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004211 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004212 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004213 MCHBAR16(0x2c20); // !!!!
4214 MCHBAR16(0x2c10); // !!!!
4215 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004216 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004217 udelay(1000);
4218 write_1d0(0, 0x33d, 0, 0);
4219 write_500(&info, 0, 0, 0xb61, 0, 0);
4220 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004221 MCHBAR32(0x1a30) = 0x0;
4222 MCHBAR32(0x1a34) = 0x0;
4223 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4224 (info.populated_ranks[0][0][0] * 0xa0);
4225 MCHBAR16(0x616) = 0x26a;
4226 MCHBAR32(0x134) = 0x856000;
4227 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004228 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4229 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004230 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004231 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4232 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004233 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004234 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004235 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4236 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004237 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4238 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4239 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4240 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4241 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4242 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4243 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4244 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4245 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4246 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004247 }
4248
4249 write_1d0(0x4, 0x151, 4, 1);
4250 write_1d0(0, 0x142, 3, 1);
4251 rdmsr(0x1ac); // !!!!
4252 write_500(&info, 1, 1, 0x6b3, 4, 1);
4253 write_500(&info, 1, 1, 0x6cf, 4, 1);
4254
4255 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4256
4257 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4258 populated_ranks[0]
4259 [0][0]) << 0),
4260 0x1d1, 3, 1);
4261 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004262 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4263 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004264 }
4265
4266 set_334(0);
4267
4268 program_base_timings(&info);
4269
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004271
4272 write_1d0(0x2, 0x1d5, 2, 1);
4273 write_1d0(0x20, 0x166, 7, 1);
4274 write_1d0(0x0, 0xeb, 3, 1);
4275 write_1d0(0x0, 0xf3, 6, 1);
4276
4277 for (channel = 0; channel < NUM_CHANNELS; channel++)
4278 for (lane = 0; lane < 9; lane++) {
4279 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4280 u8 a;
4281 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4282 write_500(&info, channel, a, addr, 6, 1);
4283 }
4284
4285 udelay(1000);
4286
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004287 if (s3resume) {
4288 if (info.cached_training == NULL) {
4289 u32 reg32;
4290 printk(BIOS_ERR,
4291 "Couldn't find training data. Rebooting\n");
4292 reg32 = inl(DEFAULT_PMBASE + 0x04);
4293 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004294 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004295 }
4296 int tm;
4297 info.training = *info.cached_training;
4298 for (tm = 0; tm < 4; tm++)
4299 for (channel = 0; channel < NUM_CHANNELS; channel++)
4300 for (slot = 0; slot < NUM_SLOTS; slot++)
4301 for (rank = 0; rank < NUM_RANKS; rank++)
4302 for (lane = 0; lane < 9; lane++)
4303 write_500(&info,
4304 channel,
4305 info.training.
4306 lane_timings
4307 [tm][channel]
4308 [slot][rank]
4309 [lane],
4310 get_timing_register_addr
4311 (lane, tm,
4312 slot, rank),
4313 9, 0);
4314 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4315 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4316 }
4317
Felix Heldf83d80b2018-07-29 05:30:30 +02004318 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004319 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004320 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004321 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004322
4323 program_board_delay(&info);
4324
Felix Held04be2dd2018-07-29 04:53:22 +02004325 MCHBAR8(0x5ff) = 0x0;
4326 MCHBAR8(0x5ff) = 0x80;
4327 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004328
Felix Held04be2dd2018-07-29 04:53:22 +02004329 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004330 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004331 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004332 gav(read_1d0(0x14b, 7)); // = 0x81023100
4333 write_1d0(0x30, 0x14b, 7, 1);
4334 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4335 write_1d0(7, 0xd6, 6, 1);
4336 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4337 write_1d0(7, 0x328, 6, 1);
4338
4339 for (channel = 0; channel < NUM_CHANNELS; channel++)
4340 set_4cf(&info, channel,
4341 info.populated_ranks[channel][0][0] ? 8 : 0);
4342
4343 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4344 write_1d0(2, 0x116, 4, 1);
4345 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4346 write_1d0(0, 0xae, 6, 1);
4347 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4348 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004349 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4350 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004351 MCHBAR32_AND(0x140, ~0x07000000);
4352 MCHBAR32_AND(0x138, ~0x07000000);
4353 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004354 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004355 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004356 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004357
4358 {
4359 u32 t;
4360 u8 val_a1;
4361 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4362 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4363 rmw_1d0(0x320, 0x07,
4364 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4365 rmw_1d0(0x14b, 0x78,
4366 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4367 4), 7,
4368 1);
4369 rmw_1d0(0xce, 0x38,
4370 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4371 4), 6,
4372 1);
4373 }
4374
4375 for (channel = 0; channel < NUM_CHANNELS; channel++)
4376 set_4cf(&info, channel,
4377 info.populated_ranks[channel][0][0] ? 9 : 1);
4378
4379 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004380 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004381 write_1d0(2, 0xae, 6, 1);
4382 write_1d0(2, 0x300, 6, 1);
4383 write_1d0(2, 0x121, 3, 1);
4384 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4385 write_1d0(4, 0xd6, 6, 1);
4386 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4387 write_1d0(4, 0x328, 6, 1);
4388
4389 for (channel = 0; channel < NUM_CHANNELS; channel++)
4390 set_4cf(&info, channel,
4391 info.populated_ranks[channel][0][0] ? 9 : 0);
4392
Felix Held04be2dd2018-07-29 04:53:22 +02004393 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4394 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004395 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004396 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004397 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4398 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4399 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4400 write_1d0(0, 0x21c, 6, 1);
4401 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4402 write_1d0(0x35, 0x14b, 7, 1);
4403
4404 for (channel = 0; channel < NUM_CHANNELS; channel++)
4405 set_4cf(&info, channel,
4406 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4407
4408 set_334(1);
4409
Felix Held04be2dd2018-07-29 04:53:22 +02004410 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004411
4412 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4413 write_500(&info, channel,
4414 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4415 1);
4416 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4417 }
Felix Held04be2dd2018-07-29 04:53:22 +02004418 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4419 MCHBAR16(0x6c0) = 0x14a0;
4420 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4421 MCHBAR16(0x232) = 0x8;
4422 /* 0x40004 or 0 depending on ? */
4423 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4424 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4425 MCHBAR32(0x128) = 0x2150d05;
4426 MCHBAR8(0x12c) = 0x1f;
4427 MCHBAR8(0x12d) = 0x56;
4428 MCHBAR8(0x12e) = 0x31;
4429 MCHBAR8(0x12f) = 0x0;
4430 MCHBAR8(0x271) = 0x2;
4431 MCHBAR8(0x671) = 0x2;
4432 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004433 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004434 MCHBAR32(0x294 + (channel << 10)) =
4435 (info.populated_ranks_mask[channel] & 3) << 16;
4436 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4437 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004438 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004439 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4440 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004441
4442 if (!s3resume)
4443 jedec_init(&info);
4444
4445 int totalrank = 0;
4446 for (channel = 0; channel < NUM_CHANNELS; channel++)
4447 for (slot = 0; slot < NUM_SLOTS; slot++)
4448 for (rank = 0; rank < NUM_RANKS; rank++)
4449 if (info.populated_ranks[channel][slot][rank]) {
4450 jedec_read(&info, channel, slot, rank,
4451 totalrank, 0xa, 0x400);
4452 totalrank++;
4453 }
4454
Felix Held04be2dd2018-07-29 04:53:22 +02004455 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004456
Felix Heldf83d80b2018-07-29 05:30:30 +02004457 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4458 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004459
4460 if (!s3resume) {
4461 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004462 MCHBAR32(0x294 + (channel << 10)) =
4463 (info.populated_ranks_mask[channel] & 3) << 16;
4464 MCHBAR16(0x298 + (channel << 10)) =
4465 info.populated_ranks[channel][0][0] |
4466 (info.populated_ranks[channel][0][1] << 5);
4467 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004468 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004469 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004470
4471 {
4472 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004473 a = MCHBAR8(0x243);
4474 b = MCHBAR8(0x643);
4475 MCHBAR8(0x243) = a | 2;
4476 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004477 }
4478
4479 write_1d0(7, 0x19b, 3, 1);
4480 write_1d0(7, 0x1c0, 3, 1);
4481 write_1d0(4, 0x1c6, 4, 1);
4482 write_1d0(4, 0x1cc, 4, 1);
4483 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4484 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004485 MCHBAR32(0x584) = 0xfffff;
4486 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004487
4488 for (channel = 0; channel < NUM_CHANNELS; channel++)
4489 for (slot = 0; slot < NUM_SLOTS; slot++)
4490 for (rank = 0; rank < NUM_RANKS; rank++)
4491 if (info.
4492 populated_ranks[channel][slot]
4493 [rank])
4494 config_rank(&info, s3resume,
4495 channel, slot,
4496 rank);
4497
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR8(0x243) = 0x1;
4499 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004500 }
4501
4502 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004503 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 write_26c(0, 0x820);
4505 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004506 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004507 /* end */
4508
4509 if (s3resume) {
4510 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004511 MCHBAR32(0x294 + (channel << 10)) =
4512 (info.populated_ranks_mask[channel] & 3) << 16;
4513 MCHBAR16(0x298 + (channel << 10)) =
4514 info.populated_ranks[channel][0][0] |
4515 (info.populated_ranks[channel][0][1] << 5);
4516 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004517 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004518 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519 }
4520
Felix Held04be2dd2018-07-29 04:53:22 +02004521 MCHBAR32_AND(0xfa4, ~0x01000002);
4522 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524 /* Before training. */
4525 timestamp_add_now(103);
4526
4527 if (!s3resume)
4528 ram_training(&info);
4529
4530 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004531 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004532
4533 dump_timings(&info);
4534
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535 program_modules_memory_map(&info, 0);
4536 program_total_memory_map(&info);
4537
4538 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004539 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004541 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004542 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004543 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004544 else
Felix Held04be2dd2018-07-29 04:53:22 +02004545 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004546
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR32_AND(0xfac, ~0x80000000);
4548 MCHBAR32(0xfb4) = 0x4800;
4549 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4550 MCHBAR32(0xe94) = 0x7ffff;
4551 MCHBAR32(0xfc0) = 0x80002040;
4552 MCHBAR32(0xfc4) = 0x701246;
4553 MCHBAR8_AND(0xfc8, ~0x70);
4554 MCHBAR32_OR(0xe5c, 0x1000000);
4555 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4556 MCHBAR32(0x50) = 0x700b0;
4557 MCHBAR32(0x3c) = 0x10;
4558 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4559 MCHBAR8_OR(0xff4, 0x2);
4560 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561
Felix Held04be2dd2018-07-29 04:53:22 +02004562 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4563 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4564 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004565
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004566 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4567 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4568 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 {
4571 u32 eax;
4572
4573 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004574 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4575 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4576 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 }
4578
4579 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583 else
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
Felix Held04be2dd2018-07-29 04:53:22 +02004586 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587
Felix Held04be2dd2018-07-29 04:53:22 +02004588 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004591 else
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 }
4594
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596
4597 {
4598 u8 al;
4599 al = 0xd;
4600 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4601 al += 2;
4602 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004603 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604 }
4605
4606 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004607 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4608 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4609 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4610 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004611 }
4612 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004613 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004614 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004615 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004616 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004617 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004618 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004619 MCHBAR8_OR(0x1210, 2);
4620 MCHBAR32(0x1200) = 0x8800440;
4621 MCHBAR32(0x1204) = 0x53ff0453;
4622 MCHBAR32(0x1208) = 0x19002043;
4623 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624
4625 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004626 MCHBAR16(0x1214) = 0x220;
4627 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004628 }
4629
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR8_OR(0x1214, 0x4);
4631 MCHBAR8(0x120c) = 0x1;
4632 MCHBAR8(0x1218) = 0x3;
4633 MCHBAR8(0x121a) = 0x3;
4634 MCHBAR8(0x121c) = 0x3;
4635 MCHBAR16(0xc14) = 0x0;
4636 MCHBAR16(0xc20) = 0x0;
4637 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638
4639 /* revision dependent here. */
4640
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642
4643 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR16_OR(0x1230, 0x8000);
4647 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648
4649 u8 bl, ebpb;
4650 u16 reg_1020;
4651
Felix Held04be2dd2018-07-29 04:53:22 +02004652 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4653 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
Felix Held04be2dd2018-07-29 04:53:22 +02004655 MCHBAR32(0x1000) = 0x100;
4656 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657
4658 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 bl = reg_1020 >> 8;
4661 ebpb = reg_1020 & 0xff;
4662 } else {
4663 ebpb = 0;
4664 bl = 8;
4665 }
4666
4667 rdmsr(0x1a2);
4668
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004670
Felix Held04be2dd2018-07-29 04:53:22 +02004671 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004672
Felix Held04be2dd2018-07-29 04:53:22 +02004673 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004674
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004677 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4678 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004679 }
4680
4681 setup_heci_uma(&info);
4682
4683 if (info.uma_enabled) {
4684 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004685 MCHBAR32_OR(0x11b0, 0x4000);
4686 MCHBAR32_OR(0x11b4, 0x4000);
4687 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688
Felix Held04be2dd2018-07-29 04:53:22 +02004689 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4690 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4691 MCHBAR16_OR(0x1170, 0x1000);
4692
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004694
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004696 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004697 ;
4698 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 }
4700
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004701 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4702 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004704 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706 udelay(1000);
4707 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004708 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4709
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710 if (!s3resume)
4711 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004712 if (s3resume && cbmem_wasnot_inited) {
4713 u32 reg32;
4714 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004715 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004716
4717 /* Clear SLP_TYPE. */
4718 reg32 = inl(DEFAULT_PMBASE + 0x04);
4719 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4720
4721 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004722 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004723 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724}