blob: c3d1b0d15fb34605087152f96edf1fd2c0d6a5c6 [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
Angel Pons244f4552021-01-15 20:41:36 +0100493static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100494{
495 u32 v;
496 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100497 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100498}
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))
Angel Pons244f4552021-01-15 20:41:36 +01001210 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001211 }
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 Ponsee7fb342021-01-28 14:11:55 +01001825 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001826 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001827 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001828 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001829 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001830 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001831 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832
Angel Ponsee7fb342021-01-28 14:11:55 +01001833 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001834 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001835
Angel Ponsee7fb342021-01-28 14:11:55 +01001836 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001837 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838 }
1839
Felix Held04be2dd2018-07-29 04:53:22 +02001840 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841
Angel Pons55f11e22020-09-14 19:06:53 +02001842 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001843
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001844 pci_write_config32(HECIDEV, 0x10, 0x0);
1845 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846}
1847
1848static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1849{
1850 int ranks_in_channel;
1851 ranks_in_channel = info->populated_ranks[channel][0][0]
1852 + info->populated_ranks[channel][0][1]
1853 + info->populated_ranks[channel][1][0]
1854 + info->populated_ranks[channel][1][1];
1855
1856 /* empty channel */
1857 if (ranks_in_channel == 0)
1858 return 1;
1859
1860 if (ranks_in_channel != ranks)
1861 return 0;
1862 /* single slot */
1863 if (info->populated_ranks[channel][0][0] !=
1864 info->populated_ranks[channel][1][0])
1865 return 1;
1866 if (info->populated_ranks[channel][0][1] !=
1867 info->populated_ranks[channel][1][1])
1868 return 1;
1869 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1870 return 0;
1871 if (info->density[channel][0] != info->density[channel][1])
1872 return 0;
1873 return 1;
1874}
1875
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001876static void read_4090(struct raminfo *info)
1877{
1878 int i, channel, slot, rank, lane;
1879 for (i = 0; i < 2; i++)
1880 for (slot = 0; slot < NUM_SLOTS; slot++)
1881 for (rank = 0; rank < NUM_RANKS; rank++)
1882 for (lane = 0; lane < 9; lane++)
1883 info->training.
1884 lane_timings[0][i][slot][rank][lane]
1885 = 32;
1886
1887 for (i = 1; i < 4; i++)
1888 for (channel = 0; channel < NUM_CHANNELS; channel++)
1889 for (slot = 0; slot < NUM_SLOTS; slot++)
1890 for (rank = 0; rank < NUM_RANKS; rank++)
1891 for (lane = 0; lane < 9; lane++) {
1892 info->training.
1893 lane_timings[i][channel]
1894 [slot][rank][lane] =
1895 read_500(info, channel,
1896 get_timing_register_addr
1897 (lane, i, slot,
1898 rank), 9)
1899 + (i == 1) * 11; // !!!!
1900 }
1901
1902}
1903
1904static u32 get_etalon2(int flip, u32 addr)
1905{
1906 const u16 invmask[] = {
1907 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1908 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1909 };
1910 u32 ret;
1911 u32 comp4 = addr / 480;
1912 addr %= 480;
1913 u32 comp1 = addr & 0xf;
1914 u32 comp2 = (addr >> 4) & 1;
1915 u32 comp3 = addr >> 5;
1916
1917 if (comp4)
1918 ret = 0x1010101 << (comp4 - 1);
1919 else
1920 ret = 0;
1921 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1922 ret = ~ret;
1923
1924 return ret;
1925}
1926
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001927static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001928{
1929 msr_t msr = {.lo = 0, .hi = 0 };
1930
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001931 wrmsr(MTRR_PHYS_BASE(3), msr);
1932 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001933}
1934
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001935static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001936{
1937 msr_t msr;
1938 msr.lo = base | MTRR_TYPE_WRPROT;
1939 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001940 wrmsr(MTRR_PHYS_BASE(3), msr);
1941 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001942 & 0xffffffff);
1943 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001944 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945}
1946
1947static void flush_cache(u32 start, u32 size)
1948{
1949 u32 end;
1950 u32 addr;
1951
1952 end = start + (ALIGN_DOWN(size + 4096, 4096));
1953 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001954 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001955}
1956
1957static void clear_errors(void)
1958{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001959 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001960}
1961
1962static void write_testing(struct raminfo *info, int totalrank, int flip)
1963{
1964 int nwrites = 0;
1965 /* in 8-byte units. */
1966 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001967 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001968
Patrick Rudolph819c2062019-11-29 19:27:37 +01001969 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970 for (offset = 0; offset < 9 * 480; offset += 2) {
1971 write32(base + offset * 8, get_etalon2(flip, offset));
1972 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1973 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1974 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1975 nwrites += 4;
1976 if (nwrites >= 320) {
1977 clear_errors();
1978 nwrites = 0;
1979 }
1980 }
1981}
1982
1983static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1984{
1985 u8 failmask = 0;
1986 int i;
1987 int comp1, comp2, comp3;
1988 u32 failxor[2] = { 0, 0 };
1989
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001990 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001991
1992 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1993 for (comp1 = 0; comp1 < 4; comp1++)
1994 for (comp2 = 0; comp2 < 60; comp2++) {
1995 u32 re[4];
1996 u32 curroffset =
1997 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1998 read128((total_rank << 28) | (curroffset << 3),
1999 (u64 *) re);
2000 failxor[0] |=
2001 get_etalon2(flip, curroffset) ^ re[0];
2002 failxor[1] |=
2003 get_etalon2(flip, curroffset) ^ re[1];
2004 failxor[0] |=
2005 get_etalon2(flip, curroffset | 1) ^ re[2];
2006 failxor[1] |=
2007 get_etalon2(flip, curroffset | 1) ^ re[3];
2008 }
2009 for (i = 0; i < 8; i++)
2010 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2011 failmask |= 1 << i;
2012 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002013 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002014 flush_cache((total_rank << 28), 1728 * 5 * 4);
2015 return failmask;
2016}
2017
2018const u32 seed1[0x18] = {
2019 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2020 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2021 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2022 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2023 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2024 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2025};
2026
2027static u32 get_seed2(int a, int b)
2028{
2029 const u32 seed2[5] = {
2030 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2031 0x5b6db6db,
2032 };
2033 u32 r;
2034 r = seed2[(a + (a >= 10)) / 5];
2035 return b ? ~r : r;
2036}
2037
2038static int make_shift(int comp2, int comp5, int x)
2039{
2040 const u8 seed3[32] = {
2041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2042 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2043 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2044 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2045 };
2046
2047 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2048}
2049
2050static u32 get_etalon(int flip, u32 addr)
2051{
2052 u32 mask_byte = 0;
2053 int comp1 = (addr >> 1) & 1;
2054 int comp2 = (addr >> 3) & 0x1f;
2055 int comp3 = (addr >> 8) & 0xf;
2056 int comp4 = (addr >> 12) & 0xf;
2057 int comp5 = (addr >> 16) & 0x1f;
2058 u32 mask_bit = ~(0x10001 << comp3);
2059 u32 part1;
2060 u32 part2;
2061 int byte;
2062
2063 part2 =
2064 ((seed1[comp5] >>
2065 make_shift(comp2, comp5,
2066 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2067 part1 =
2068 ((seed1[comp5] >>
2069 make_shift(comp2, comp5,
2070 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2071
2072 for (byte = 0; byte < 4; byte++)
2073 if ((get_seed2(comp5, comp4) >>
2074 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2075 mask_byte |= 0xff << (8 * byte);
2076
2077 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2078 (comp3 + 16));
2079}
2080
2081static void
2082write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2083 char flip)
2084{
2085 int i;
2086 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002087 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2088 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002089}
2090
2091static u8
2092check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2093 char flip)
2094{
2095 u8 failmask = 0;
2096 u32 failxor[2];
2097 int i;
2098 int comp1, comp2, comp3;
2099
2100 failxor[0] = 0;
2101 failxor[1] = 0;
2102
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002103 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002104 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2105 for (comp1 = 0; comp1 < 16; comp1++)
2106 for (comp2 = 0; comp2 < 64; comp2++) {
2107 u32 addr =
2108 (totalrank << 28) | (region << 25) | (block
2109 << 16)
2110 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2111 2);
2112 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002113 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002114 }
2115 for (i = 0; i < 8; i++)
2116 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2117 failmask |= 1 << i;
2118 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002119 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002120 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2121 return failmask;
2122}
2123
2124static int check_bounded(unsigned short *vals, u16 bound)
2125{
2126 int i;
2127
2128 for (i = 0; i < 8; i++)
2129 if (vals[i] < bound)
2130 return 0;
2131 return 1;
2132}
2133
2134enum state {
2135 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2136};
2137
2138static int validate_state(enum state *in)
2139{
2140 int i;
2141 for (i = 0; i < 8; i++)
2142 if (in[i] != COMPLETE)
2143 return 0;
2144 return 1;
2145}
2146
2147static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002148do_fsm(enum state *state, u16 *counter,
2149 u8 fail_mask, int margin, int uplimit,
2150 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002151{
2152 int lane;
2153
2154 for (lane = 0; lane < 8; lane++) {
2155 int is_fail = (fail_mask >> lane) & 1;
2156 switch (state[lane]) {
2157 case BEFORE_USABLE:
2158 if (!is_fail) {
2159 counter[lane] = 1;
2160 state[lane] = AT_USABLE;
2161 break;
2162 }
2163 counter[lane] = 0;
2164 state[lane] = BEFORE_USABLE;
2165 break;
2166 case AT_USABLE:
2167 if (!is_fail) {
2168 ++counter[lane];
2169 if (counter[lane] >= margin) {
2170 state[lane] = AT_MARGIN;
2171 res_low[lane] = val - margin + 1;
2172 break;
2173 }
2174 state[lane] = 1;
2175 break;
2176 }
2177 counter[lane] = 0;
2178 state[lane] = BEFORE_USABLE;
2179 break;
2180 case AT_MARGIN:
2181 if (is_fail) {
2182 state[lane] = COMPLETE;
2183 res_high[lane] = val - 1;
2184 } else {
2185 counter[lane]++;
2186 state[lane] = AT_MARGIN;
2187 if (val == uplimit) {
2188 state[lane] = COMPLETE;
2189 res_high[lane] = uplimit;
2190 }
2191 }
2192 break;
2193 case COMPLETE:
2194 break;
2195 }
2196 }
2197}
2198
2199static void
2200train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2201 u8 total_rank, u8 reg_178, int first_run, int niter,
2202 timing_bounds_t * timings)
2203{
2204 int lane;
2205 enum state state[8];
2206 u16 count[8];
2207 u8 lower_usable[8];
2208 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002209 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002210 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002211 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002212
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002213 for (i = 0; i < 8; i++)
2214 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002215
2216 if (!first_run) {
2217 int is_all_ok = 1;
2218 for (lane = 0; lane < 8; lane++)
2219 if (timings[reg_178][channel][slot][rank][lane].
2220 smallest ==
2221 timings[reg_178][channel][slot][rank][lane].
2222 largest) {
2223 timings[reg_178][channel][slot][rank][lane].
2224 smallest = 0;
2225 timings[reg_178][channel][slot][rank][lane].
2226 largest = 0;
2227 is_all_ok = 0;
2228 }
2229 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002230 for (i = 0; i < 8; i++)
2231 state[i] = COMPLETE;
2232 }
2233 }
2234
2235 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2236 u8 failmask = 0;
2237 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2238 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2239 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002240 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002241 do_fsm(state, count, failmask, 5, 47, lower_usable,
2242 upper_usable, reg1b3);
2243 }
2244
2245 if (reg1b3) {
2246 write_1d0(0, 0x1b3, 6, 1);
2247 write_1d0(0, 0x1a3, 6, 1);
2248 for (lane = 0; lane < 8; lane++) {
2249 if (state[lane] == COMPLETE) {
2250 timings[reg_178][channel][slot][rank][lane].
2251 smallest =
2252 lower_usable[lane] +
2253 (info->training.
2254 lane_timings[0][channel][slot][rank][lane]
2255 & 0x3F) - 32;
2256 timings[reg_178][channel][slot][rank][lane].
2257 largest =
2258 upper_usable[lane] +
2259 (info->training.
2260 lane_timings[0][channel][slot][rank][lane]
2261 & 0x3F) - 32;
2262 }
2263 }
2264 }
2265
2266 if (!first_run) {
2267 for (lane = 0; lane < 8; lane++)
2268 if (state[lane] == COMPLETE) {
2269 write_500(info, channel,
2270 timings[reg_178][channel][slot][rank]
2271 [lane].smallest,
2272 get_timing_register_addr(lane, 0,
2273 slot, rank),
2274 9, 1);
2275 write_500(info, channel,
2276 timings[reg_178][channel][slot][rank]
2277 [lane].smallest +
2278 info->training.
2279 lane_timings[1][channel][slot][rank]
2280 [lane]
2281 -
2282 info->training.
2283 lane_timings[0][channel][slot][rank]
2284 [lane], get_timing_register_addr(lane,
2285 1,
2286 slot,
2287 rank),
2288 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002289 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002290 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002291 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002292
2293 do {
2294 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002295 for (i = 0; i < niter; i++) {
2296 if (failmask == 0xFF)
2297 break;
2298 failmask |=
2299 check_testing_type2(info, total_rank, 2, i,
2300 0);
2301 failmask |=
2302 check_testing_type2(info, total_rank, 3, i,
2303 1);
2304 }
Felix Held04be2dd2018-07-29 04:53:22 +02002305 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002307 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308 if ((1 << lane) & failmask) {
2309 if (timings[reg_178][channel]
2310 [slot][rank][lane].
2311 largest <=
2312 timings[reg_178][channel]
2313 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002314 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002315 [lane] = -1;
2316 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002317 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002318 [lane] = 0;
2319 timings[reg_178]
2320 [channel][slot]
2321 [rank][lane].
2322 smallest++;
2323 write_500(info, channel,
2324 timings
2325 [reg_178]
2326 [channel]
2327 [slot][rank]
2328 [lane].
2329 smallest,
2330 get_timing_register_addr
2331 (lane, 0,
2332 slot, rank),
2333 9, 1);
2334 write_500(info, channel,
2335 timings
2336 [reg_178]
2337 [channel]
2338 [slot][rank]
2339 [lane].
2340 smallest +
2341 info->
2342 training.
2343 lane_timings
2344 [1][channel]
2345 [slot][rank]
2346 [lane]
2347 -
2348 info->
2349 training.
2350 lane_timings
2351 [0][channel]
2352 [slot][rank]
2353 [lane],
2354 get_timing_register_addr
2355 (lane, 1,
2356 slot, rank),
2357 9, 1);
2358 }
2359 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002360 num_successfully_checked[lane]
2361 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002362 }
2363 }
Felix Held04be2dd2018-07-29 04:53:22 +02002364 while (!check_bounded(num_successfully_checked, 2))
2365 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002366
2367 for (lane = 0; lane < 8; lane++)
2368 if (state[lane] == COMPLETE) {
2369 write_500(info, channel,
2370 timings[reg_178][channel][slot][rank]
2371 [lane].largest,
2372 get_timing_register_addr(lane, 0,
2373 slot, rank),
2374 9, 1);
2375 write_500(info, channel,
2376 timings[reg_178][channel][slot][rank]
2377 [lane].largest +
2378 info->training.
2379 lane_timings[1][channel][slot][rank]
2380 [lane]
2381 -
2382 info->training.
2383 lane_timings[0][channel][slot][rank]
2384 [lane], get_timing_register_addr(lane,
2385 1,
2386 slot,
2387 rank),
2388 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002389 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002390 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002391 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002392
2393 do {
2394 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002395 for (i = 0; i < niter; i++) {
2396 if (failmask == 0xFF)
2397 break;
2398 failmask |=
2399 check_testing_type2(info, total_rank, 2, i,
2400 0);
2401 failmask |=
2402 check_testing_type2(info, total_rank, 3, i,
2403 1);
2404 }
2405
Felix Held04be2dd2018-07-29 04:53:22 +02002406 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002407 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002408 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002409 if ((1 << lane) & failmask) {
2410 if (timings[reg_178][channel]
2411 [slot][rank][lane].
2412 largest <=
2413 timings[reg_178][channel]
2414 [slot][rank][lane].
2415 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002416 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002417 [lane] = -1;
2418 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002419 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002420 [lane] = 0;
2421 timings[reg_178]
2422 [channel][slot]
2423 [rank][lane].
2424 largest--;
2425 write_500(info, channel,
2426 timings
2427 [reg_178]
2428 [channel]
2429 [slot][rank]
2430 [lane].
2431 largest,
2432 get_timing_register_addr
2433 (lane, 0,
2434 slot, rank),
2435 9, 1);
2436 write_500(info, channel,
2437 timings
2438 [reg_178]
2439 [channel]
2440 [slot][rank]
2441 [lane].
2442 largest +
2443 info->
2444 training.
2445 lane_timings
2446 [1][channel]
2447 [slot][rank]
2448 [lane]
2449 -
2450 info->
2451 training.
2452 lane_timings
2453 [0][channel]
2454 [slot][rank]
2455 [lane],
2456 get_timing_register_addr
2457 (lane, 1,
2458 slot, rank),
2459 9, 1);
2460 }
2461 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002462 num_successfully_checked[lane]
2463 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002464 }
2465 }
2466 }
Felix Held04be2dd2018-07-29 04:53:22 +02002467 while (!check_bounded(num_successfully_checked, 3))
2468 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002469
2470 for (lane = 0; lane < 8; lane++) {
2471 write_500(info, channel,
2472 info->training.
2473 lane_timings[0][channel][slot][rank][lane],
2474 get_timing_register_addr(lane, 0, slot, rank),
2475 9, 1);
2476 write_500(info, channel,
2477 info->training.
2478 lane_timings[1][channel][slot][rank][lane],
2479 get_timing_register_addr(lane, 1, slot, rank),
2480 9, 1);
2481 if (timings[reg_178][channel][slot][rank][lane].
2482 largest <=
2483 timings[reg_178][channel][slot][rank][lane].
2484 smallest) {
2485 timings[reg_178][channel][slot][rank][lane].
2486 largest = 0;
2487 timings[reg_178][channel][slot][rank][lane].
2488 smallest = 0;
2489 }
2490 }
2491 }
2492}
2493
2494static void set_10b(struct raminfo *info, u8 val)
2495{
2496 int channel;
2497 int slot, rank;
2498 int lane;
2499
2500 if (read_1d0(0x10b, 6) == val)
2501 return;
2502
2503 write_1d0(val, 0x10b, 6, 1);
2504
2505 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2506 u16 reg_500;
2507 reg_500 = read_500(info, channel,
2508 get_timing_register_addr(lane, 0, slot,
2509 rank), 9);
2510 if (val == 1) {
2511 if (lut16[info->clock_speed_index] <= reg_500)
2512 reg_500 -= lut16[info->clock_speed_index];
2513 else
2514 reg_500 = 0;
2515 } else {
2516 reg_500 += lut16[info->clock_speed_index];
2517 }
2518 write_500(info, channel, reg_500,
2519 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2520 }
2521}
2522
2523static void set_ecc(int onoff)
2524{
2525 int channel;
2526 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2527 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002528 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002529 if (onoff)
2530 t |= 1;
2531 else
2532 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002533 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002534 }
2535}
2536
2537static void set_178(u8 val)
2538{
2539 if (val >= 31)
2540 val = val - 31;
2541 else
2542 val = 63 - val;
2543
2544 write_1d0(2 * val, 0x178, 7, 1);
2545}
2546
2547static void
2548write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2549 int type)
2550{
2551 int lane;
2552
2553 for (lane = 0; lane < 8; lane++)
2554 write_500(info, channel,
2555 info->training.
2556 lane_timings[type][channel][slot][rank][lane],
2557 get_timing_register_addr(lane, type, slot, rank), 9,
2558 0);
2559}
2560
2561static void
2562try_timing_offsets(struct raminfo *info, int channel,
2563 int slot, int rank, int totalrank)
2564{
2565 u16 count[8];
2566 enum state state[8];
2567 u8 lower_usable[8], upper_usable[8];
2568 int lane;
2569 int i;
2570 int flip = 1;
2571 int timing_offset;
2572
2573 for (i = 0; i < 8; i++)
2574 state[i] = BEFORE_USABLE;
2575
2576 memset(count, 0, sizeof(count));
2577
2578 for (lane = 0; lane < 8; lane++)
2579 write_500(info, channel,
2580 info->training.
2581 lane_timings[2][channel][slot][rank][lane] + 32,
2582 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2583
2584 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2585 timing_offset++) {
2586 u8 failmask;
2587 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2588 failmask = 0;
2589 for (i = 0; i < 2 && failmask != 0xff; i++) {
2590 flip = !flip;
2591 write_testing(info, totalrank, flip);
2592 failmask |= check_testing(info, totalrank, flip);
2593 }
2594 do_fsm(state, count, failmask, 10, 63, lower_usable,
2595 upper_usable, timing_offset);
2596 }
2597 write_1d0(0, 0x1bb, 6, 1);
2598 dump_timings(info);
2599 if (!validate_state(state))
2600 die("Couldn't discover DRAM timings (1)\n");
2601
2602 for (lane = 0; lane < 8; lane++) {
2603 u8 bias = 0;
2604
2605 if (info->silicon_revision) {
2606 int usable_length;
2607
2608 usable_length = upper_usable[lane] - lower_usable[lane];
2609 if (usable_length >= 20) {
2610 bias = usable_length / 2 - 10;
2611 if (bias >= 2)
2612 bias = 2;
2613 }
2614 }
2615 write_500(info, channel,
2616 info->training.
2617 lane_timings[2][channel][slot][rank][lane] +
2618 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2619 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2620 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2621 info->training.lane_timings[2][channel][slot][rank][lane] +
2622 lower_usable[lane];
2623 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2624 info->training.lane_timings[2][channel][slot][rank][lane] +
2625 upper_usable[lane];
2626 info->training.timing2_offset[channel][slot][rank][lane] =
2627 info->training.lane_timings[2][channel][slot][rank][lane];
2628 }
2629}
2630
2631static u8
2632choose_training(struct raminfo *info, int channel, int slot, int rank,
2633 int lane, timing_bounds_t * timings, u8 center_178)
2634{
2635 u16 central_weight;
2636 u16 side_weight;
2637 unsigned int sum = 0, count = 0;
2638 u8 span;
2639 u8 lower_margin, upper_margin;
2640 u8 reg_178;
2641 u8 result;
2642
2643 span = 12;
2644 central_weight = 20;
2645 side_weight = 20;
2646 if (info->silicon_revision == 1 && channel == 1) {
2647 central_weight = 5;
2648 side_weight = 20;
2649 if ((info->
2650 populated_ranks_mask[1] ^ (info->
2651 populated_ranks_mask[1] >> 2)) &
2652 1)
2653 span = 18;
2654 }
2655 if ((info->populated_ranks_mask[0] & 5) == 5) {
2656 central_weight = 20;
2657 side_weight = 20;
2658 }
2659 if (info->clock_speed_index >= 2
2660 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2661 if (info->silicon_revision == 1) {
2662 switch (channel) {
2663 case 0:
2664 if (lane == 1) {
2665 central_weight = 10;
2666 side_weight = 20;
2667 }
2668 break;
2669 case 1:
2670 if (lane == 6) {
2671 side_weight = 5;
2672 central_weight = 20;
2673 }
2674 break;
2675 }
2676 }
2677 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2678 side_weight = 5;
2679 central_weight = 20;
2680 }
2681 }
2682 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2683 reg_178 += span) {
2684 u8 smallest;
2685 u8 largest;
2686 largest = timings[reg_178][channel][slot][rank][lane].largest;
2687 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2688 if (largest - smallest + 1 >= 5) {
2689 unsigned int weight;
2690 if (reg_178 == center_178)
2691 weight = central_weight;
2692 else
2693 weight = side_weight;
2694 sum += weight * (largest + smallest);
2695 count += weight;
2696 }
2697 }
2698 dump_timings(info);
2699 if (count == 0)
2700 die("Couldn't discover DRAM timings (2)\n");
2701 result = sum / (2 * count);
2702 lower_margin =
2703 result - timings[center_178][channel][slot][rank][lane].smallest;
2704 upper_margin =
2705 timings[center_178][channel][slot][rank][lane].largest - result;
2706 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002707 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002708 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002709 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002710 return result;
2711}
2712
2713#define STANDARD_MIN_MARGIN 5
2714
2715static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2716{
2717 u16 margin[64];
2718 int lane, rank, slot, channel;
2719 u8 reg178;
2720 int count = 0, sum = 0;
2721
2722 for (reg178 = reg178_min[info->clock_speed_index];
2723 reg178 < reg178_max[info->clock_speed_index];
2724 reg178 += reg178_step[info->clock_speed_index]) {
2725 margin[reg178] = -1;
2726 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2727 int curmargin =
2728 timings[reg178][channel][slot][rank][lane].largest -
2729 timings[reg178][channel][slot][rank][lane].
2730 smallest + 1;
2731 if (curmargin < margin[reg178])
2732 margin[reg178] = curmargin;
2733 }
2734 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2735 u16 weight;
2736 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2737 sum += weight * reg178;
2738 count += weight;
2739 }
2740 }
2741 dump_timings(info);
2742 if (count == 0)
2743 die("Couldn't discover DRAM timings (3)\n");
2744
2745 u8 threshold;
2746
2747 for (threshold = 30; threshold >= 5; threshold--) {
2748 int usable_length = 0;
2749 int smallest_fount = 0;
2750 for (reg178 = reg178_min[info->clock_speed_index];
2751 reg178 < reg178_max[info->clock_speed_index];
2752 reg178 += reg178_step[info->clock_speed_index])
2753 if (margin[reg178] >= threshold) {
2754 usable_length +=
2755 reg178_step[info->clock_speed_index];
2756 info->training.reg178_largest =
2757 reg178 -
2758 2 * reg178_step[info->clock_speed_index];
2759
2760 if (!smallest_fount) {
2761 smallest_fount = 1;
2762 info->training.reg178_smallest =
2763 reg178 +
2764 reg178_step[info->
2765 clock_speed_index];
2766 }
2767 }
2768 if (usable_length >= 0x21)
2769 break;
2770 }
2771
2772 return sum / count;
2773}
2774
2775static int check_cached_sanity(struct raminfo *info)
2776{
2777 int lane;
2778 int slot, rank;
2779 int channel;
2780
2781 if (!info->cached_training)
2782 return 0;
2783
2784 for (channel = 0; channel < NUM_CHANNELS; channel++)
2785 for (slot = 0; slot < NUM_SLOTS; slot++)
2786 for (rank = 0; rank < NUM_RANKS; rank++)
2787 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2788 u16 cached_value, estimation_value;
2789 cached_value =
2790 info->cached_training->
2791 lane_timings[1][channel][slot][rank]
2792 [lane];
2793 if (cached_value >= 0x18
2794 && cached_value <= 0x1E7) {
2795 estimation_value =
2796 info->training.
2797 lane_timings[1][channel]
2798 [slot][rank][lane];
2799 if (estimation_value <
2800 cached_value - 24)
2801 return 0;
2802 if (estimation_value >
2803 cached_value + 24)
2804 return 0;
2805 }
2806 }
2807 return 1;
2808}
2809
2810static int try_cached_training(struct raminfo *info)
2811{
2812 u8 saved_243[2];
2813 u8 tm;
2814
2815 int channel, slot, rank, lane;
2816 int flip = 1;
2817 int i, j;
2818
2819 if (!check_cached_sanity(info))
2820 return 0;
2821
2822 info->training.reg178_center = info->cached_training->reg178_center;
2823 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2824 info->training.reg178_largest = info->cached_training->reg178_largest;
2825 memcpy(&info->training.timing_bounds,
2826 &info->cached_training->timing_bounds,
2827 sizeof(info->training.timing_bounds));
2828 memcpy(&info->training.timing_offset,
2829 &info->cached_training->timing_offset,
2830 sizeof(info->training.timing_offset));
2831
2832 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002833 saved_243[0] = MCHBAR8(0x243);
2834 saved_243[1] = MCHBAR8(0x643);
2835 MCHBAR8(0x243) = saved_243[0] | 2;
2836 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002837 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002838 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002839 if (read_1d0(0x10b, 6) & 1)
2840 set_10b(info, 0);
2841 for (tm = 0; tm < 2; tm++) {
2842 int totalrank;
2843
2844 set_178(tm ? info->cached_training->reg178_largest : info->
2845 cached_training->reg178_smallest);
2846
2847 totalrank = 0;
2848 /* Check timing ranges. With i == 0 we check smallest one and with
2849 i == 1 the largest bound. With j == 0 we check that on the bound
2850 it still works whereas with j == 1 we check that just outside of
2851 bound we fail.
2852 */
2853 FOR_POPULATED_RANKS_BACKWARDS {
2854 for (i = 0; i < 2; i++) {
2855 for (lane = 0; lane < 8; lane++) {
2856 write_500(info, channel,
2857 info->cached_training->
2858 timing2_bounds[channel][slot]
2859 [rank][lane][i],
2860 get_timing_register_addr(lane,
2861 3,
2862 slot,
2863 rank),
2864 9, 1);
2865
2866 if (!i)
2867 write_500(info, channel,
2868 info->
2869 cached_training->
2870 timing2_offset
2871 [channel][slot][rank]
2872 [lane],
2873 get_timing_register_addr
2874 (lane, 2, slot, rank),
2875 9, 1);
2876 write_500(info, channel,
2877 i ? info->cached_training->
2878 timing_bounds[tm][channel]
2879 [slot][rank][lane].
2880 largest : info->
2881 cached_training->
2882 timing_bounds[tm][channel]
2883 [slot][rank][lane].smallest,
2884 get_timing_register_addr(lane,
2885 0,
2886 slot,
2887 rank),
2888 9, 1);
2889 write_500(info, channel,
2890 info->cached_training->
2891 timing_offset[channel][slot]
2892 [rank][lane] +
2893 (i ? info->cached_training->
2894 timing_bounds[tm][channel]
2895 [slot][rank][lane].
2896 largest : info->
2897 cached_training->
2898 timing_bounds[tm][channel]
2899 [slot][rank][lane].
2900 smallest) - 64,
2901 get_timing_register_addr(lane,
2902 1,
2903 slot,
2904 rank),
2905 9, 1);
2906 }
2907 for (j = 0; j < 2; j++) {
2908 u8 failmask;
2909 u8 expected_failmask;
2910 char reg1b3;
2911
2912 reg1b3 = (j == 1) + 4;
2913 reg1b3 =
2914 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2915 write_1d0(reg1b3, 0x1bb, 6, 1);
2916 write_1d0(reg1b3, 0x1b3, 6, 1);
2917 write_1d0(reg1b3, 0x1a3, 6, 1);
2918
2919 flip = !flip;
2920 write_testing(info, totalrank, flip);
2921 failmask =
2922 check_testing(info, totalrank,
2923 flip);
2924 expected_failmask =
2925 j == 0 ? 0x00 : 0xff;
2926 if (failmask != expected_failmask)
2927 goto fail;
2928 }
2929 }
2930 totalrank++;
2931 }
2932 }
2933
2934 set_178(info->cached_training->reg178_center);
2935 if (info->use_ecc)
2936 set_ecc(1);
2937 write_training_data(info);
2938 write_1d0(0, 322, 3, 1);
2939 info->training = *info->cached_training;
2940
2941 write_1d0(0, 0x1bb, 6, 1);
2942 write_1d0(0, 0x1b3, 6, 1);
2943 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002944 MCHBAR8(0x243) = saved_243[0];
2945 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002946
2947 return 1;
2948
2949fail:
2950 FOR_POPULATED_RANKS {
2951 write_500_timings_type(info, channel, slot, rank, 1);
2952 write_500_timings_type(info, channel, slot, rank, 2);
2953 write_500_timings_type(info, channel, slot, rank, 3);
2954 }
2955
2956 write_1d0(0, 0x1bb, 6, 1);
2957 write_1d0(0, 0x1b3, 6, 1);
2958 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002959 MCHBAR8(0x243) = saved_243[0];
2960 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002961
2962 return 0;
2963}
2964
2965static void do_ram_training(struct raminfo *info)
2966{
2967 u8 saved_243[2];
2968 int totalrank = 0;
2969 u8 reg_178;
2970 int niter;
2971
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002972 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002973 int lane, rank, slot, channel;
2974 u8 reg178_center;
2975
2976 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002977 saved_243[0] = MCHBAR8(0x243);
2978 saved_243[1] = MCHBAR8(0x643);
2979 MCHBAR8(0x243) = saved_243[0] | 2;
2980 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002981 switch (info->clock_speed_index) {
2982 case 0:
2983 niter = 5;
2984 break;
2985 case 1:
2986 niter = 10;
2987 break;
2988 default:
2989 niter = 19;
2990 break;
2991 }
2992 set_ecc(0);
2993
2994 FOR_POPULATED_RANKS_BACKWARDS {
2995 int i;
2996
2997 write_500_timings_type(info, channel, slot, rank, 0);
2998
2999 write_testing(info, totalrank, 0);
3000 for (i = 0; i < niter; i++) {
3001 write_testing_type2(info, totalrank, 2, i, 0);
3002 write_testing_type2(info, totalrank, 3, i, 1);
3003 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003004 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003005 totalrank++;
3006 }
3007
3008 if (reg178_min[info->clock_speed_index] <
3009 reg178_max[info->clock_speed_index])
3010 memset(timings[reg178_min[info->clock_speed_index]], 0,
3011 sizeof(timings[0]) *
3012 (reg178_max[info->clock_speed_index] -
3013 reg178_min[info->clock_speed_index]));
3014 for (reg_178 = reg178_min[info->clock_speed_index];
3015 reg_178 < reg178_max[info->clock_speed_index];
3016 reg_178 += reg178_step[info->clock_speed_index]) {
3017 totalrank = 0;
3018 set_178(reg_178);
3019 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3020 for (slot = 0; slot < NUM_SLOTS; slot++)
3021 for (rank = 0; rank < NUM_RANKS; rank++) {
3022 memset(&timings[reg_178][channel][slot]
3023 [rank][0].smallest, 0, 16);
3024 if (info->
3025 populated_ranks[channel][slot]
3026 [rank]) {
3027 train_ram_at_178(info, channel,
3028 slot, rank,
3029 totalrank,
3030 reg_178, 1,
3031 niter,
3032 timings);
3033 totalrank++;
3034 }
3035 }
3036 }
3037
3038 reg178_center = choose_reg178(info, timings);
3039
3040 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3041 info->training.timing_bounds[0][channel][slot][rank][lane].
3042 smallest =
3043 timings[info->training.
3044 reg178_smallest][channel][slot][rank][lane].
3045 smallest;
3046 info->training.timing_bounds[0][channel][slot][rank][lane].
3047 largest =
3048 timings[info->training.
3049 reg178_smallest][channel][slot][rank][lane].largest;
3050 info->training.timing_bounds[1][channel][slot][rank][lane].
3051 smallest =
3052 timings[info->training.
3053 reg178_largest][channel][slot][rank][lane].smallest;
3054 info->training.timing_bounds[1][channel][slot][rank][lane].
3055 largest =
3056 timings[info->training.
3057 reg178_largest][channel][slot][rank][lane].largest;
3058 info->training.timing_offset[channel][slot][rank][lane] =
3059 info->training.lane_timings[1][channel][slot][rank][lane]
3060 -
3061 info->training.lane_timings[0][channel][slot][rank][lane] +
3062 64;
3063 }
3064
3065 if (info->silicon_revision == 1
3066 && (info->
3067 populated_ranks_mask[1] ^ (info->
3068 populated_ranks_mask[1] >> 2)) & 1) {
3069 int ranks_after_channel1;
3070
3071 totalrank = 0;
3072 for (reg_178 = reg178_center - 18;
3073 reg_178 <= reg178_center + 18; reg_178 += 18) {
3074 totalrank = 0;
3075 set_178(reg_178);
3076 for (slot = 0; slot < NUM_SLOTS; slot++)
3077 for (rank = 0; rank < NUM_RANKS; rank++) {
3078 if (info->
3079 populated_ranks[1][slot][rank]) {
3080 train_ram_at_178(info, 1, slot,
3081 rank,
3082 totalrank,
3083 reg_178, 0,
3084 niter,
3085 timings);
3086 totalrank++;
3087 }
3088 }
3089 }
3090 ranks_after_channel1 = totalrank;
3091
3092 for (reg_178 = reg178_center - 12;
3093 reg_178 <= reg178_center + 12; reg_178 += 12) {
3094 totalrank = ranks_after_channel1;
3095 set_178(reg_178);
3096 for (slot = 0; slot < NUM_SLOTS; slot++)
3097 for (rank = 0; rank < NUM_RANKS; rank++)
3098 if (info->
3099 populated_ranks[0][slot][rank]) {
3100 train_ram_at_178(info, 0, slot,
3101 rank,
3102 totalrank,
3103 reg_178, 0,
3104 niter,
3105 timings);
3106 totalrank++;
3107 }
3108
3109 }
3110 } else {
3111 for (reg_178 = reg178_center - 12;
3112 reg_178 <= reg178_center + 12; reg_178 += 12) {
3113 totalrank = 0;
3114 set_178(reg_178);
3115 FOR_POPULATED_RANKS_BACKWARDS {
3116 train_ram_at_178(info, channel, slot, rank,
3117 totalrank, reg_178, 0, niter,
3118 timings);
3119 totalrank++;
3120 }
3121 }
3122 }
3123
3124 set_178(reg178_center);
3125 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3126 u16 tm0;
3127
3128 tm0 =
3129 choose_training(info, channel, slot, rank, lane, timings,
3130 reg178_center);
3131 write_500(info, channel, tm0,
3132 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3133 write_500(info, channel,
3134 tm0 +
3135 info->training.
3136 lane_timings[1][channel][slot][rank][lane] -
3137 info->training.
3138 lane_timings[0][channel][slot][rank][lane],
3139 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3140 }
3141
3142 totalrank = 0;
3143 FOR_POPULATED_RANKS_BACKWARDS {
3144 try_timing_offsets(info, channel, slot, rank, totalrank);
3145 totalrank++;
3146 }
Felix Held04be2dd2018-07-29 04:53:22 +02003147 MCHBAR8(0x243) = saved_243[0];
3148 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003149 write_1d0(0, 0x142, 3, 1);
3150 info->training.reg178_center = reg178_center;
3151}
3152
3153static void ram_training(struct raminfo *info)
3154{
3155 u16 saved_fc4;
3156
Felix Held04be2dd2018-07-29 04:53:22 +02003157 saved_fc4 = MCHBAR16(0xfc4);
3158 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003159
3160 if (info->revision >= 8)
3161 read_4090(info);
3162
3163 if (!try_cached_training(info))
3164 do_ram_training(info);
3165 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3166 && info->clock_speed_index < 2)
3167 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003168 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003169}
3170
Martin Roth468d02c2019-10-23 21:44:42 -06003171static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003172{
Martin Roth468d02c2019-10-23 21:44:42 -06003173 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003174 if (a > b) {
3175 t = a;
3176 a = b;
3177 b = t;
3178 }
3179 /* invariant a < b. */
3180 while (a) {
3181 t = b % a;
3182 b = a;
3183 a = t;
3184 }
3185 return b;
3186}
3187
3188static inline int div_roundup(int a, int b)
3189{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003190 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003191}
3192
Martin Roth468d02c2019-10-23 21:44:42 -06003193static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003194{
3195 return (a * b) / gcd(a, b);
3196}
3197
3198struct stru1 {
3199 u8 freqs_reversed;
3200 u8 freq_diff_reduced;
3201 u8 freq_min_reduced;
3202 u8 divisor_f4_to_fmax;
3203 u8 divisor_f3_to_fmax;
3204 u8 freq4_to_max_remainder;
3205 u8 freq3_to_2_remainder;
3206 u8 freq3_to_2_remaindera;
3207 u8 freq4_to_2_remainder;
3208 int divisor_f3_to_f1, divisor_f4_to_f2;
3209 int common_time_unit_ps;
3210 int freq_max_reduced;
3211};
3212
3213static void
3214compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3215 int num_cycles_2, int num_cycles_1, int round_it,
3216 int add_freqs, struct stru1 *result)
3217{
3218 int g;
3219 int common_time_unit_ps;
3220 int freq1_reduced, freq2_reduced;
3221 int freq_min_reduced;
3222 int freq_max_reduced;
3223 int freq3, freq4;
3224
3225 g = gcd(freq1, freq2);
3226 freq1_reduced = freq1 / g;
3227 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003228 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3229 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003230
3231 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3232 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3233 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3234 if (add_freqs) {
3235 freq3 += freq2_reduced;
3236 freq4 += freq1_reduced;
3237 }
3238
3239 if (round_it) {
3240 result->freq3_to_2_remainder = 0;
3241 result->freq3_to_2_remaindera = 0;
3242 result->freq4_to_max_remainder = 0;
3243 result->divisor_f4_to_f2 = 0;
3244 result->divisor_f3_to_f1 = 0;
3245 } else {
3246 if (freq2_reduced < freq1_reduced) {
3247 result->freq3_to_2_remainder =
3248 result->freq3_to_2_remaindera =
3249 freq3 % freq1_reduced - freq1_reduced + 1;
3250 result->freq4_to_max_remainder =
3251 -(freq4 % freq1_reduced);
3252 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3253 result->divisor_f4_to_f2 =
3254 (freq4 -
3255 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3256 result->freq4_to_2_remainder =
3257 -(char)((freq1_reduced - freq2_reduced) +
3258 ((u8) freq4 -
3259 (freq1_reduced -
3260 freq2_reduced)) % (u8) freq2_reduced);
3261 } else {
3262 if (freq2_reduced > freq1_reduced) {
3263 result->freq4_to_max_remainder =
3264 (freq4 % freq2_reduced) - freq2_reduced + 1;
3265 result->freq4_to_2_remainder =
3266 freq4 % freq_max_reduced -
3267 freq_max_reduced + 1;
3268 } else {
3269 result->freq4_to_max_remainder =
3270 -(freq4 % freq2_reduced);
3271 result->freq4_to_2_remainder =
3272 -(char)(freq4 % freq_max_reduced);
3273 }
3274 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3275 result->divisor_f3_to_f1 =
3276 (freq3 -
3277 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3278 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3279 result->freq3_to_2_remaindera =
3280 -(char)((freq_max_reduced - freq_min_reduced) +
3281 (freq3 -
3282 (freq_max_reduced -
3283 freq_min_reduced)) % freq1_reduced);
3284 }
3285 }
3286 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3287 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3288 if (round_it) {
3289 if (freq2_reduced > freq1_reduced) {
3290 if (freq3 % freq_max_reduced)
3291 result->divisor_f3_to_fmax++;
3292 }
3293 if (freq2_reduced < freq1_reduced) {
3294 if (freq4 % freq_max_reduced)
3295 result->divisor_f4_to_fmax++;
3296 }
3297 }
3298 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3299 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3300 result->freq_min_reduced = freq_min_reduced;
3301 result->common_time_unit_ps = common_time_unit_ps;
3302 result->freq_max_reduced = freq_max_reduced;
3303}
3304
3305static void
3306set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3307 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3308 int num_cycles_4, int reverse)
3309{
3310 struct stru1 vv;
3311 char multiplier;
3312
3313 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3314 0, 1, &vv);
3315
3316 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003317 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003318 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3319 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3320 div_roundup(num_cycles_1,
3321 vv.common_time_unit_ps) +
3322 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3323 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3324
3325 u32 y =
3326 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3327 vv.freq_max_reduced * multiplier)
3328 | (vv.
3329 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3330 multiplier) << 16) | ((u8) (vv.
3331 freq_min_reduced
3332 *
3333 multiplier)
3334 << 24);
3335 u32 x =
3336 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3337 divisor_f3_to_f1
3338 << 16)
3339 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3340 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003341 MCHBAR32(reg) = y;
3342 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003343 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003344 MCHBAR32(reg + 4) = y;
3345 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003346 }
3347}
3348
3349static void
3350set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3351 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3352 int num_cycles_4)
3353{
3354 struct stru1 ratios1;
3355 struct stru1 ratios2;
3356
3357 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3358 0, 1, &ratios2);
3359 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3360 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003361 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003362 ratios1.freq4_to_max_remainder | (ratios2.
3363 freq4_to_max_remainder
3364 << 8)
3365 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3366 divisor_f4_to_fmax
3367 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003368 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3369 (ratios2.freq4_to_max_remainder << 8) |
3370 (ratios1.divisor_f4_to_fmax << 16) |
3371 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003372}
3373
3374static void
3375set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3376 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3377{
3378 struct stru1 ratios;
3379
3380 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3381 round_it, add_freqs, &ratios);
3382 switch (mode) {
3383 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003384 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3385 (ratios.freqs_reversed << 8);
3386 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3387 (ratios.freq4_to_max_remainder << 8) |
3388 (ratios.divisor_f3_to_fmax << 16) |
3389 (ratios.divisor_f4_to_fmax << 20) |
3390 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003391 break;
3392
3393 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003394 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3395 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003396 break;
3397
3398 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003399 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3400 (ratios.freq4_to_max_remainder << 8) |
3401 (ratios.divisor_f3_to_fmax << 16) |
3402 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003403 break;
3404
3405 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003406 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3407 (ratios.divisor_f4_to_fmax << 8) |
3408 (ratios.freqs_reversed << 12) |
3409 (ratios.freq_min_reduced << 16) |
3410 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003411 break;
3412 }
3413}
3414
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003415static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416{
3417 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3418 0, 1);
3419 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3420 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3421 1);
3422 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3423 frequency_11(info), 1231, 1524, 0, 1);
3424 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3425 frequency_11(info) / 2, 1278, 2008, 0, 1);
3426 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3427 1167, 1539, 0, 1);
3428 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3429 frequency_11(info) / 2, 1403, 1318, 0, 1);
3430 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3431 1);
3432 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3433 1);
3434 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3435 1, 1);
3436 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3437 1);
3438 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3439 frequency_11(info) / 2, 4000, 0, 0, 0);
3440 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3441 frequency_11(info) / 2, 4000, 4000, 0, 0);
3442
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003443 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003444 printk(RAM_SPEW, "[6dc] <= %x\n",
3445 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003446 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003447 } else
3448 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3449 info->delay46_ps[0], 0,
3450 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003451 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3452 frequency_11(info), 2500, 0, 0, 0);
3453 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3454 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003455 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003456 printk(RAM_SPEW, "[6e8] <= %x\n",
3457 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003458 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003459 } else
3460 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3461 info->delay46_ps[1], 0,
3462 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003463 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3464 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3465 470, 0);
3466 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3467 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3468 454, 459, 0);
3469 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3470 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3471 2588, 0);
3472 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3473 2405, 0);
3474 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3475 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3476 480, 0);
3477 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003478 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3479 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003480}
3481
3482static u16 get_max_timing(struct raminfo *info, int channel)
3483{
3484 int slot, rank, lane;
3485 u16 ret = 0;
3486
Felix Held04be2dd2018-07-29 04:53:22 +02003487 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488 return 384;
3489
3490 if (info->revision < 8)
3491 return 256;
3492
3493 for (slot = 0; slot < NUM_SLOTS; slot++)
3494 for (rank = 0; rank < NUM_RANKS; rank++)
3495 if (info->populated_ranks[channel][slot][rank])
3496 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003497 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003498 get_timing_register_addr
3499 (lane, 0, slot,
3500 rank), 9));
3501 return ret;
3502}
3503
3504static void set_274265(struct raminfo *info)
3505{
3506 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3507 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3508 int delay_e_over_cycle_ps;
3509 int cycletime_ps;
3510 int channel;
3511
3512 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003513 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3515 cycletime_ps =
3516 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3517 delay_d_ps =
3518 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3519 - info->some_delay_3_ps_rounded + 200;
3520 if (!
3521 ((info->silicon_revision == 0
3522 || info->silicon_revision == 1)
3523 && (info->revision >= 8)))
3524 delay_d_ps += halfcycle_ps(info) * 2;
3525 delay_d_ps +=
3526 halfcycle_ps(info) * (!info->revision_flag_1 +
3527 info->some_delay_2_halfcycles_ceil +
3528 2 * info->some_delay_1_cycle_floor +
3529 info->clock_speed_index +
3530 2 * info->cas_latency - 7 + 11);
3531 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3532
Felix Held04be2dd2018-07-29 04:53:22 +02003533 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3534 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3535 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003536 delay_d_ps += 650;
3537 delay_c_ps = delay_d_ps + 1800;
3538 if (delay_c_ps <= delay_a_ps)
3539 delay_e_ps = 0;
3540 else
3541 delay_e_ps =
3542 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3543 cycletime_ps);
3544
3545 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3546 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3547 delay_f_cycles =
3548 div_roundup(2500 - delay_e_over_cycle_ps,
3549 2 * halfcycle_ps(info));
3550 if (delay_f_cycles > delay_e_cycles) {
3551 info->delay46_ps[channel] = delay_e_ps;
3552 delay_e_cycles = 0;
3553 } else {
3554 info->delay46_ps[channel] =
3555 delay_e_over_cycle_ps +
3556 2 * halfcycle_ps(info) * delay_f_cycles;
3557 delay_e_cycles -= delay_f_cycles;
3558 }
3559
3560 if (info->delay46_ps[channel] < 2500) {
3561 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003562 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003563 }
3564 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3565 if (delay_b_ps <= delay_a_ps)
3566 delay_b_ps = 0;
3567 else
3568 delay_b_ps -= delay_a_ps;
3569 info->delay54_ps[channel] =
3570 cycletime_ps * div_roundup(delay_b_ps,
3571 cycletime_ps) -
3572 2 * halfcycle_ps(info) * delay_e_cycles;
3573 if (info->delay54_ps[channel] < 2500)
3574 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003575 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003576 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3577 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003578 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003580 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003581 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3582 4 * halfcycle_ps(info)) - 6;
3583 MCHBAR32((channel << 10) + 0x274) =
3584 info->training.reg274265[channel][1] |
3585 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003586 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003587 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3588 4 * halfcycle_ps(info)) + 1;
3589 MCHBAR16((channel << 10) + 0x265) =
3590 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003591 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003592 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003593 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003594 else
Felix Held04be2dd2018-07-29 04:53:22 +02003595 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003596}
3597
3598static void restore_274265(struct raminfo *info)
3599{
3600 int channel;
3601
3602 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003603 MCHBAR32((channel << 10) + 0x274) =
3604 (info->cached_training->reg274265[channel][0] << 16) |
3605 info->cached_training->reg274265[channel][1];
3606 MCHBAR16((channel << 10) + 0x265) =
3607 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003609 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003610 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611 else
Felix Held04be2dd2018-07-29 04:53:22 +02003612 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613}
3614
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615static void dmi_setup(void)
3616{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003617 gav(DMIBAR8(0x254));
3618 DMIBAR8(0x254) = 0x1;
3619 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003620 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621
Angel Ponsd071c4d2020-09-14 23:51:35 +02003622 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623
3624 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3625 DEFAULT_GPIOBASE | 0x38);
3626 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3627}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003629void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003632 u16 ggc;
3633 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634
Felix Held04be2dd2018-07-29 04:53:22 +02003635 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3637 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003638 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003639 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003641
3642 dmi_setup();
3643
Felix Held04be2dd2018-07-29 04:53:22 +02003644 MCHBAR16(0x1170) = 0xa880;
3645 MCHBAR8(0x11c1) = 0x1;
3646 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003647 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003649 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3650 /* 0 for 32MB */
3651 gfxsize = 0;
3652 }
3653
3654 ggc = 0xb00 | ((gfxsize + 5) << 4);
3655
Angel Pons16fe1e02020-07-22 16:12:33 +02003656 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
3658 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003659 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003660
3661 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003662 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003663 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR16_OR(0x2c30, 0x200);
3665 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003666 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003667 pci_read_config8(GMA, MSAC); // = 0x2
3668 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003669 RCBA8(0x2318);
3670 RCBA8(0x2318) = 0x47;
3671 RCBA8(0x2320);
3672 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 }
3674
Felix Heldf83d80b2018-07-29 05:30:30 +02003675 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676
Angel Pons16fe1e02020-07-22 16:12:33 +02003677 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003678 gav(RCBA32(0x3428));
3679 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003680}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003681
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003682void raminit(const int s3resume, const u8 *spd_addrmap)
3683{
Martin Roth468d02c2019-10-23 21:44:42 -06003684 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003685 int i;
3686 struct raminfo info;
3687 u8 x2ca8;
3688 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003689 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003690
Felix Held04be2dd2018-07-29 04:53:22 +02003691 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003692
3693 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3694
Angel Pons16fe1e02020-07-22 16:12:33 +02003695 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003696
3697 memset(&info, 0x5a, sizeof(info));
3698
3699 info.last_500_command[0] = 0;
3700 info.last_500_command[1] = 0;
3701
3702 info.fsb_frequency = 135 * 2;
3703 info.board_lane_delay[0] = 0x14;
3704 info.board_lane_delay[1] = 0x07;
3705 info.board_lane_delay[2] = 0x07;
3706 info.board_lane_delay[3] = 0x08;
3707 info.board_lane_delay[4] = 0x56;
3708 info.board_lane_delay[5] = 0x04;
3709 info.board_lane_delay[6] = 0x04;
3710 info.board_lane_delay[7] = 0x05;
3711 info.board_lane_delay[8] = 0x10;
3712
3713 info.training.reg_178 = 0;
3714 info.training.reg_10b = 0;
3715
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003716 info.memory_reserved_for_heci_mb = 0;
3717
3718 /* before SPD */
3719 timestamp_add_now(101);
3720
Felix Held29a9c072018-07-29 01:34:45 +02003721 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003722 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723
3724 collect_system_info(&info);
3725
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003726 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3727
3728 info.use_ecc = 1;
3729 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003730 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003731 int v;
3732 int try;
3733 int addr;
3734 const u8 useful_addresses[] = {
3735 DEVICE_TYPE,
3736 MODULE_TYPE,
3737 DENSITY,
3738 RANKS_AND_DQ,
3739 MEMORY_BUS_WIDTH,
3740 TIMEBASE_DIVIDEND,
3741 TIMEBASE_DIVISOR,
3742 CYCLETIME,
3743 CAS_LATENCIES_LSB,
3744 CAS_LATENCIES_MSB,
3745 CAS_LATENCY_TIME,
3746 0x11, 0x12, 0x13, 0x14, 0x15,
3747 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3748 0x1c, 0x1d,
3749 THERMAL_AND_REFRESH,
3750 0x20,
3751 REFERENCE_RAW_CARD_USED,
3752 RANK1_ADDRESS_MAPPING,
3753 0x75, 0x76, 0x77, 0x78,
3754 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3755 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3756 0x85, 0x86, 0x87, 0x88,
3757 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3758 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3759 0x95
3760 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003761 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003762 continue;
3763 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003764 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765 DEVICE_TYPE);
3766 if (v >= 0)
3767 break;
3768 }
3769 if (v < 0)
3770 continue;
3771 for (addr = 0;
3772 addr <
3773 sizeof(useful_addresses) /
3774 sizeof(useful_addresses[0]); addr++)
3775 gav(info.
3776 spd[channel][0][useful_addresses
3777 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003778 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779 useful_addresses
3780 [addr]));
3781 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3782 die("Only DDR3 is supported");
3783
3784 v = info.spd[channel][0][RANKS_AND_DQ];
3785 info.populated_ranks[channel][0][0] = 1;
3786 info.populated_ranks[channel][0][1] =
3787 ((v >> 3) & 7);
3788 if (((v >> 3) & 7) > 1)
3789 die("At most 2 ranks are supported");
3790 if ((v & 7) == 0 || (v & 7) > 2)
3791 die("Only x8 and x16 modules are supported");
3792 if ((info.
3793 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3794 && (info.
3795 spd[channel][slot][MODULE_TYPE] & 0xF)
3796 != 3)
3797 die("Registered memory is not supported");
3798 info.is_x16_module[channel][0] = (v & 7) - 1;
3799 info.density[channel][slot] =
3800 info.spd[channel][slot][DENSITY] & 0xF;
3801 if (!
3802 (info.
3803 spd[channel][slot][MEMORY_BUS_WIDTH] &
3804 0x18))
3805 info.use_ecc = 0;
3806 }
3807
3808 gav(0x55);
3809
3810 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3811 int v = 0;
3812 for (slot = 0; slot < NUM_SLOTS; slot++)
3813 for (rank = 0; rank < NUM_RANKS; rank++)
3814 v |= info.
3815 populated_ranks[channel][slot][rank]
3816 << (2 * slot + rank);
3817 info.populated_ranks_mask[channel] = v;
3818 }
3819
3820 gav(0x55);
3821
Angel Pons16fe1e02020-07-22 16:12:33 +02003822 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003823 }
3824
3825 /* after SPD */
3826 timestamp_add_now(102);
3827
Felix Held04be2dd2018-07-29 04:53:22 +02003828 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003829
3830 collect_system_info(&info);
3831 calculate_timings(&info);
3832
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003833 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003834 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835 if (x2ca8 == 0 && (reg8 & 0x80)) {
3836 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3837 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3838 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3839 */
3840
3841 /* Clear bit7. */
3842
3843 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3844 (reg8 & ~(1 << 7)));
3845
3846 printk(BIOS_INFO,
3847 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003848 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003849 }
3850 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851
3852 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003853 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3854 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855
3856 compute_derived_timings(&info);
3857
3858 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003859 gav(MCHBAR8(0x164));
3860 MCHBAR8(0x164) = 0x26;
3861 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862 }
3863
Felix Held04be2dd2018-07-29 04:53:22 +02003864 MCHBAR32_OR(0x18b4, 0x210000);
3865 MCHBAR32_OR(0x1890, 0x2000000);
3866 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867
Angel Ponsa457e352020-07-22 18:17:33 +02003868 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3869 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003870
Felix Held04be2dd2018-07-29 04:53:22 +02003871 gav(MCHBAR16(0x2c10));
3872 MCHBAR16(0x2c10) = 0x412;
3873 gav(MCHBAR16(0x2c10));
3874 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875
Felix Held04be2dd2018-07-29 04:53:22 +02003876 gav(MCHBAR8(0x2ca8)); // !!!!
3877 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003878
Angel Ponsa457e352020-07-22 18:17:33 +02003879 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3880 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003881 gav(MCHBAR32(0x1c04)); // !!!!
3882 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003883
3884 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003885 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003886 }
3887
Felix Held04be2dd2018-07-29 04:53:22 +02003888 MCHBAR32(0x18d8) = 0x120000;
3889 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003890 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3891 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003892 MCHBAR32(0x18d8) = 0x40000;
3893 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003894 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003896 MCHBAR32(0x18d8) = 0x180000;
3897 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003898 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3899 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003900 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003901
Felix Held04be2dd2018-07-29 04:53:22 +02003902 gav(MCHBAR32(0x18dc)); // !!!!
3903 MCHBAR32(0x18dc) = 0x3;
3904 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905
3906 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003907 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003908 }
3909
Felix Held04be2dd2018-07-29 04:53:22 +02003910 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003911 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003912 MCHBAR32(0x1a10) = 0x4200010e;
3913 MCHBAR32_OR(0x18b8, 0x200);
3914 gav(MCHBAR32(0x1918)); // !!!!
3915 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
Felix Held04be2dd2018-07-29 04:53:22 +02003917 gav(MCHBAR32(0x18b8)); // !!!!
3918 MCHBAR32(0x18b8) = 0xe00;
3919 gav(MCHBAR32(0x182c)); // !!!!
3920 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003921 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3922 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003923 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3924 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925
Felix Held04be2dd2018-07-29 04:53:22 +02003926 MCHBAR32_AND(0x18b4, 0xffff7fff);
3927 gav(MCHBAR32(0x1a68)); // !!!!
3928 MCHBAR32(0x1a68) = 0x343800;
3929 gav(MCHBAR32(0x1e68)); // !!!!
3930 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003931
3932 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003933 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003934 }
3935
Angel Pons08143572020-07-22 17:47:06 +02003936 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3937 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3938 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3939 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3940 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003941 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3942 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003943 gav(MCHBAR32(0x1af0)); // !!!!
3944 gav(MCHBAR32(0x1af0)); // !!!!
3945 MCHBAR32(0x1af0) = 0x1f020003;
3946 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003947
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003948 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950 }
3951
Felix Held04be2dd2018-07-29 04:53:22 +02003952 gav(MCHBAR32(0x1890)); // !!!!
3953 MCHBAR32(0x1890) = 0x80102;
3954 gav(MCHBAR32(0x18b4)); // !!!!
3955 MCHBAR32(0x18b4) = 0x216000;
3956 MCHBAR32(0x18a4) = 0x22222222;
3957 MCHBAR32(0x18a8) = 0x22222222;
3958 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003959
3960 udelay(1000);
3961
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003962 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003963
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003964 if (x2ca8 == 0) {
3965 int j;
3966 if (s3resume && info.cached_training) {
3967 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003968 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003969 info.cached_training->reg2ca9_bit0);
3970 for (i = 0; i < 2; i++)
3971 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003972 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003973 i, j, info.cached_training->reg274265[i][j]);
3974 } else {
3975 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003976 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003977 info.training.reg2ca9_bit0);
3978 for (i = 0; i < 2; i++)
3979 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003980 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003981 i, j, info.training.reg274265[i][j]);
3982 }
3983
3984 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003985
3986 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003987 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003988 }
3989
3990 udelay(1000);
3991
3992 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003993 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003994 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003995 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3996 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3997 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003998
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003999 MCHBAR8(0x1150);
4000 MCHBAR8(0x1151);
4001 MCHBAR8(0x1022);
4002 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004003 MCHBAR32(0x1300) = 0x60606060;
4004 MCHBAR32(0x1304) = 0x60606060;
4005 MCHBAR32(0x1308) = 0x78797a7b;
4006 MCHBAR32(0x130c) = 0x7c7d7e7f;
4007 MCHBAR32(0x1310) = 0x60606060;
4008 MCHBAR32(0x1314) = 0x60606060;
4009 MCHBAR32(0x1318) = 0x60606060;
4010 MCHBAR32(0x131c) = 0x60606060;
4011 MCHBAR32(0x1320) = 0x50515253;
4012 MCHBAR32(0x1324) = 0x54555657;
4013 MCHBAR32(0x1328) = 0x58595a5b;
4014 MCHBAR32(0x132c) = 0x5c5d5e5f;
4015 MCHBAR32(0x1330) = 0x40414243;
4016 MCHBAR32(0x1334) = 0x44454647;
4017 MCHBAR32(0x1338) = 0x48494a4b;
4018 MCHBAR32(0x133c) = 0x4c4d4e4f;
4019 MCHBAR32(0x1340) = 0x30313233;
4020 MCHBAR32(0x1344) = 0x34353637;
4021 MCHBAR32(0x1348) = 0x38393a3b;
4022 MCHBAR32(0x134c) = 0x3c3d3e3f;
4023 MCHBAR32(0x1350) = 0x20212223;
4024 MCHBAR32(0x1354) = 0x24252627;
4025 MCHBAR32(0x1358) = 0x28292a2b;
4026 MCHBAR32(0x135c) = 0x2c2d2e2f;
4027 MCHBAR32(0x1360) = 0x10111213;
4028 MCHBAR32(0x1364) = 0x14151617;
4029 MCHBAR32(0x1368) = 0x18191a1b;
4030 MCHBAR32(0x136c) = 0x1c1d1e1f;
4031 MCHBAR32(0x1370) = 0x10203;
4032 MCHBAR32(0x1374) = 0x4050607;
4033 MCHBAR32(0x1378) = 0x8090a0b;
4034 MCHBAR32(0x137c) = 0xc0d0e0f;
4035 MCHBAR8(0x11cc) = 0x4e;
4036 MCHBAR32(0x1110) = 0x73970404;
4037 MCHBAR32(0x1114) = 0x72960404;
4038 MCHBAR32(0x1118) = 0x6f950404;
4039 MCHBAR32(0x111c) = 0x6d940404;
4040 MCHBAR32(0x1120) = 0x6a930404;
4041 MCHBAR32(0x1124) = 0x68a41404;
4042 MCHBAR32(0x1128) = 0x66a21404;
4043 MCHBAR32(0x112c) = 0x63a01404;
4044 MCHBAR32(0x1130) = 0x609e1404;
4045 MCHBAR32(0x1134) = 0x5f9c1404;
4046 MCHBAR32(0x1138) = 0x5c961404;
4047 MCHBAR32(0x113c) = 0x58a02404;
4048 MCHBAR32(0x1140) = 0x54942404;
4049 MCHBAR32(0x1190) = 0x900080a;
4050 MCHBAR16(0x11c0) = 0xc40b;
4051 MCHBAR16(0x11c2) = 0x303;
4052 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004053 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004054 MCHBAR32(0x11b8) = 0x70c3000;
4055 MCHBAR8(0x11ec) = 0xa;
4056 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004057 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004058 MCHBAR16(0x11ca) = 0xfa;
4059 MCHBAR32(0x11e4) = 0x4e20;
4060 MCHBAR8(0x11bc) = 0xf;
4061 MCHBAR16(0x11da) = 0x19;
4062 MCHBAR16(0x11ba) = 0x470c;
4063 MCHBAR32(0x1680) = 0xe6ffe4ff;
4064 MCHBAR32(0x1684) = 0xdeffdaff;
4065 MCHBAR32(0x1688) = 0xd4ffd0ff;
4066 MCHBAR32(0x168c) = 0xccffc6ff;
4067 MCHBAR32(0x1690) = 0xc0ffbeff;
4068 MCHBAR32(0x1694) = 0xb8ffb0ff;
4069 MCHBAR32(0x1698) = 0xa8ff0000;
4070 MCHBAR32(0x169c) = 0xc00;
4071 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004072 }
4073
Felix Held04be2dd2018-07-29 04:53:22 +02004074 MCHBAR32(0x124c) = 0x15040d00;
4075 MCHBAR32(0x1250) = 0x7f0000;
4076 MCHBAR32(0x1254) = 0x1e220004;
4077 MCHBAR32(0x1258) = 0x4000004;
4078 MCHBAR32(0x1278) = 0x0;
4079 MCHBAR32(0x125c) = 0x0;
4080 MCHBAR32(0x1260) = 0x0;
4081 MCHBAR32(0x1264) = 0x0;
4082 MCHBAR32(0x1268) = 0x0;
4083 MCHBAR32(0x126c) = 0x0;
4084 MCHBAR32(0x1270) = 0x0;
4085 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004086 }
4087
4088 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004089 MCHBAR16(0x1214) = 0x320;
4090 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004091 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4092 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004093 MCHBAR32(0x1400) = 0x13040020;
4094 MCHBAR32(0x1404) = 0xe090120;
4095 MCHBAR32(0x1408) = 0x5120220;
4096 MCHBAR32(0x140c) = 0x5120330;
4097 MCHBAR32(0x1410) = 0xe090220;
4098 MCHBAR32(0x1414) = 0x1010001;
4099 MCHBAR32(0x1418) = 0x1110000;
4100 MCHBAR32(0x141c) = 0x9020020;
4101 MCHBAR32(0x1420) = 0xd090220;
4102 MCHBAR32(0x1424) = 0x2090220;
4103 MCHBAR32(0x1428) = 0x2090330;
4104 MCHBAR32(0x142c) = 0xd090220;
4105 MCHBAR32(0x1430) = 0x1010001;
4106 MCHBAR32(0x1434) = 0x1110000;
4107 MCHBAR32(0x1438) = 0x11040020;
4108 MCHBAR32(0x143c) = 0x4030220;
4109 MCHBAR32(0x1440) = 0x1060220;
4110 MCHBAR32(0x1444) = 0x1060330;
4111 MCHBAR32(0x1448) = 0x4030220;
4112 MCHBAR32(0x144c) = 0x1010001;
4113 MCHBAR32(0x1450) = 0x1110000;
4114 MCHBAR32(0x1454) = 0x4010020;
4115 MCHBAR32(0x1458) = 0xb090220;
4116 MCHBAR32(0x145c) = 0x1090220;
4117 MCHBAR32(0x1460) = 0x1090330;
4118 MCHBAR32(0x1464) = 0xb090220;
4119 MCHBAR32(0x1468) = 0x1010001;
4120 MCHBAR32(0x146c) = 0x1110000;
4121 MCHBAR32(0x1470) = 0xf040020;
4122 MCHBAR32(0x1474) = 0xa090220;
4123 MCHBAR32(0x1478) = 0x1120220;
4124 MCHBAR32(0x147c) = 0x1120330;
4125 MCHBAR32(0x1480) = 0xa090220;
4126 MCHBAR32(0x1484) = 0x1010001;
4127 MCHBAR32(0x1488) = 0x1110000;
4128 MCHBAR32(0x148c) = 0x7020020;
4129 MCHBAR32(0x1490) = 0x1010220;
4130 MCHBAR32(0x1494) = 0x10210;
4131 MCHBAR32(0x1498) = 0x10320;
4132 MCHBAR32(0x149c) = 0x1010220;
4133 MCHBAR32(0x14a0) = 0x1010001;
4134 MCHBAR32(0x14a4) = 0x1110000;
4135 MCHBAR32(0x14a8) = 0xd040020;
4136 MCHBAR32(0x14ac) = 0x8090220;
4137 MCHBAR32(0x14b0) = 0x1111310;
4138 MCHBAR32(0x14b4) = 0x1111420;
4139 MCHBAR32(0x14b8) = 0x8090220;
4140 MCHBAR32(0x14bc) = 0x1010001;
4141 MCHBAR32(0x14c0) = 0x1110000;
4142 MCHBAR32(0x14c4) = 0x3010020;
4143 MCHBAR32(0x14c8) = 0x7090220;
4144 MCHBAR32(0x14cc) = 0x1081310;
4145 MCHBAR32(0x14d0) = 0x1081420;
4146 MCHBAR32(0x14d4) = 0x7090220;
4147 MCHBAR32(0x14d8) = 0x1010001;
4148 MCHBAR32(0x14dc) = 0x1110000;
4149 MCHBAR32(0x14e0) = 0xb040020;
4150 MCHBAR32(0x14e4) = 0x2030220;
4151 MCHBAR32(0x14e8) = 0x1051310;
4152 MCHBAR32(0x14ec) = 0x1051420;
4153 MCHBAR32(0x14f0) = 0x2030220;
4154 MCHBAR32(0x14f4) = 0x1010001;
4155 MCHBAR32(0x14f8) = 0x1110000;
4156 MCHBAR32(0x14fc) = 0x5020020;
4157 MCHBAR32(0x1500) = 0x5090220;
4158 MCHBAR32(0x1504) = 0x2071310;
4159 MCHBAR32(0x1508) = 0x2071420;
4160 MCHBAR32(0x150c) = 0x5090220;
4161 MCHBAR32(0x1510) = 0x1010001;
4162 MCHBAR32(0x1514) = 0x1110000;
4163 MCHBAR32(0x1518) = 0x7040120;
4164 MCHBAR32(0x151c) = 0x2090220;
4165 MCHBAR32(0x1520) = 0x70b1210;
4166 MCHBAR32(0x1524) = 0x70b1310;
4167 MCHBAR32(0x1528) = 0x2090220;
4168 MCHBAR32(0x152c) = 0x1010001;
4169 MCHBAR32(0x1530) = 0x1110000;
4170 MCHBAR32(0x1534) = 0x1010110;
4171 MCHBAR32(0x1538) = 0x1081310;
4172 MCHBAR32(0x153c) = 0x5041200;
4173 MCHBAR32(0x1540) = 0x5041310;
4174 MCHBAR32(0x1544) = 0x1081310;
4175 MCHBAR32(0x1548) = 0x1010001;
4176 MCHBAR32(0x154c) = 0x1110000;
4177 MCHBAR32(0x1550) = 0x1040120;
4178 MCHBAR32(0x1554) = 0x4051210;
4179 MCHBAR32(0x1558) = 0xd051200;
4180 MCHBAR32(0x155c) = 0xd051200;
4181 MCHBAR32(0x1560) = 0x4051210;
4182 MCHBAR32(0x1564) = 0x1010001;
4183 MCHBAR32(0x1568) = 0x1110000;
4184 MCHBAR16(0x1222) = 0x220a;
4185 MCHBAR16(0x123c) = 0x1fc0;
4186 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004187 }
4188
Felix Heldf83d80b2018-07-29 05:30:30 +02004189 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004190 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004191 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004192
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004193 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004194
4195 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004196 MCHBAR8_AND(0x2ca8, ~3);
4197 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004198 /* This issues a CPU reset without resetting the platform */
4199 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004200 /* Write back the S3 state to PM1_CNT to let the reset CPU
4201 know it also needs to take the s3 path. */
4202 if (s3resume)
4203 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4204 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004205 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004206 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004207 }
4208
Felix Held04be2dd2018-07-29 04:53:22 +02004209 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004210 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004211 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004212 MCHBAR16(0x2c20); // !!!!
4213 MCHBAR16(0x2c10); // !!!!
4214 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004215 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004216 udelay(1000);
4217 write_1d0(0, 0x33d, 0, 0);
4218 write_500(&info, 0, 0, 0xb61, 0, 0);
4219 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004220 MCHBAR32(0x1a30) = 0x0;
4221 MCHBAR32(0x1a34) = 0x0;
4222 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4223 (info.populated_ranks[0][0][0] * 0xa0);
4224 MCHBAR16(0x616) = 0x26a;
4225 MCHBAR32(0x134) = 0x856000;
4226 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004227 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4228 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004229 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004230 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4231 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004232 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004233 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004234 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4235 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004236 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4237 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4238 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4239 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4240 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4241 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4242 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4243 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4244 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4245 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004246 }
4247
4248 write_1d0(0x4, 0x151, 4, 1);
4249 write_1d0(0, 0x142, 3, 1);
4250 rdmsr(0x1ac); // !!!!
4251 write_500(&info, 1, 1, 0x6b3, 4, 1);
4252 write_500(&info, 1, 1, 0x6cf, 4, 1);
4253
Angel Pons244f4552021-01-15 20:41:36 +01004254 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004255
4256 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4257 populated_ranks[0]
4258 [0][0]) << 0),
4259 0x1d1, 3, 1);
4260 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004261 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4262 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004263 }
4264
4265 set_334(0);
4266
4267 program_base_timings(&info);
4268
Felix Held04be2dd2018-07-29 04:53:22 +02004269 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270
4271 write_1d0(0x2, 0x1d5, 2, 1);
4272 write_1d0(0x20, 0x166, 7, 1);
4273 write_1d0(0x0, 0xeb, 3, 1);
4274 write_1d0(0x0, 0xf3, 6, 1);
4275
4276 for (channel = 0; channel < NUM_CHANNELS; channel++)
4277 for (lane = 0; lane < 9; lane++) {
4278 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4279 u8 a;
4280 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4281 write_500(&info, channel, a, addr, 6, 1);
4282 }
4283
4284 udelay(1000);
4285
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004286 if (s3resume) {
4287 if (info.cached_training == NULL) {
4288 u32 reg32;
4289 printk(BIOS_ERR,
4290 "Couldn't find training data. Rebooting\n");
4291 reg32 = inl(DEFAULT_PMBASE + 0x04);
4292 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004293 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004294 }
4295 int tm;
4296 info.training = *info.cached_training;
4297 for (tm = 0; tm < 4; tm++)
4298 for (channel = 0; channel < NUM_CHANNELS; channel++)
4299 for (slot = 0; slot < NUM_SLOTS; slot++)
4300 for (rank = 0; rank < NUM_RANKS; rank++)
4301 for (lane = 0; lane < 9; lane++)
4302 write_500(&info,
4303 channel,
4304 info.training.
4305 lane_timings
4306 [tm][channel]
4307 [slot][rank]
4308 [lane],
4309 get_timing_register_addr
4310 (lane, tm,
4311 slot, rank),
4312 9, 0);
4313 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4314 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4315 }
4316
Felix Heldf83d80b2018-07-29 05:30:30 +02004317 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004318 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004319 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004320 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004321
4322 program_board_delay(&info);
4323
Felix Held04be2dd2018-07-29 04:53:22 +02004324 MCHBAR8(0x5ff) = 0x0;
4325 MCHBAR8(0x5ff) = 0x80;
4326 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004327
Felix Held04be2dd2018-07-29 04:53:22 +02004328 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004329 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004330 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004331 gav(read_1d0(0x14b, 7)); // = 0x81023100
4332 write_1d0(0x30, 0x14b, 7, 1);
4333 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4334 write_1d0(7, 0xd6, 6, 1);
4335 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4336 write_1d0(7, 0x328, 6, 1);
4337
4338 for (channel = 0; channel < NUM_CHANNELS; channel++)
4339 set_4cf(&info, channel,
4340 info.populated_ranks[channel][0][0] ? 8 : 0);
4341
4342 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4343 write_1d0(2, 0x116, 4, 1);
4344 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4345 write_1d0(0, 0xae, 6, 1);
4346 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4347 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004348 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4349 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004350 MCHBAR32_AND(0x140, ~0x07000000);
4351 MCHBAR32_AND(0x138, ~0x07000000);
4352 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004353 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004354 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004355 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004356
4357 {
4358 u32 t;
4359 u8 val_a1;
4360 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4361 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4362 rmw_1d0(0x320, 0x07,
Angel Pons244f4552021-01-15 20:41:36 +01004363 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004364 rmw_1d0(0x14b, 0x78,
4365 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004366 4), 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004367 rmw_1d0(0xce, 0x38,
4368 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004369 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004370 }
4371
4372 for (channel = 0; channel < NUM_CHANNELS; channel++)
4373 set_4cf(&info, channel,
4374 info.populated_ranks[channel][0][0] ? 9 : 1);
4375
Angel Pons244f4552021-01-15 20:41:36 +01004376 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004377 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004378 write_1d0(2, 0xae, 6, 1);
4379 write_1d0(2, 0x300, 6, 1);
4380 write_1d0(2, 0x121, 3, 1);
4381 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4382 write_1d0(4, 0xd6, 6, 1);
4383 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4384 write_1d0(4, 0x328, 6, 1);
4385
4386 for (channel = 0; channel < NUM_CHANNELS; channel++)
4387 set_4cf(&info, channel,
4388 info.populated_ranks[channel][0][0] ? 9 : 0);
4389
Felix Held04be2dd2018-07-29 04:53:22 +02004390 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4391 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004392 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004393 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004394 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4395 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4396 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4397 write_1d0(0, 0x21c, 6, 1);
4398 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4399 write_1d0(0x35, 0x14b, 7, 1);
4400
4401 for (channel = 0; channel < NUM_CHANNELS; channel++)
4402 set_4cf(&info, channel,
4403 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4404
4405 set_334(1);
4406
Felix Held04be2dd2018-07-29 04:53:22 +02004407 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004408
4409 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4410 write_500(&info, channel,
4411 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4412 1);
4413 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4414 }
Felix Held04be2dd2018-07-29 04:53:22 +02004415 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4416 MCHBAR16(0x6c0) = 0x14a0;
4417 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4418 MCHBAR16(0x232) = 0x8;
4419 /* 0x40004 or 0 depending on ? */
4420 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4421 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4422 MCHBAR32(0x128) = 0x2150d05;
4423 MCHBAR8(0x12c) = 0x1f;
4424 MCHBAR8(0x12d) = 0x56;
4425 MCHBAR8(0x12e) = 0x31;
4426 MCHBAR8(0x12f) = 0x0;
4427 MCHBAR8(0x271) = 0x2;
4428 MCHBAR8(0x671) = 0x2;
4429 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004430 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004431 MCHBAR32(0x294 + (channel << 10)) =
4432 (info.populated_ranks_mask[channel] & 3) << 16;
4433 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4434 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004435 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004436 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4437 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004438
4439 if (!s3resume)
4440 jedec_init(&info);
4441
4442 int totalrank = 0;
4443 for (channel = 0; channel < NUM_CHANNELS; channel++)
4444 for (slot = 0; slot < NUM_SLOTS; slot++)
4445 for (rank = 0; rank < NUM_RANKS; rank++)
4446 if (info.populated_ranks[channel][slot][rank]) {
4447 jedec_read(&info, channel, slot, rank,
4448 totalrank, 0xa, 0x400);
4449 totalrank++;
4450 }
4451
Felix Held04be2dd2018-07-29 04:53:22 +02004452 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004453
Felix Heldf83d80b2018-07-29 05:30:30 +02004454 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4455 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004456
4457 if (!s3resume) {
4458 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004459 MCHBAR32(0x294 + (channel << 10)) =
4460 (info.populated_ranks_mask[channel] & 3) << 16;
4461 MCHBAR16(0x298 + (channel << 10)) =
4462 info.populated_ranks[channel][0][0] |
4463 (info.populated_ranks[channel][0][1] << 5);
4464 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004465 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004466 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004467
4468 {
4469 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004470 a = MCHBAR8(0x243);
4471 b = MCHBAR8(0x643);
4472 MCHBAR8(0x243) = a | 2;
4473 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004474 }
4475
4476 write_1d0(7, 0x19b, 3, 1);
4477 write_1d0(7, 0x1c0, 3, 1);
4478 write_1d0(4, 0x1c6, 4, 1);
4479 write_1d0(4, 0x1cc, 4, 1);
4480 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4481 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004482 MCHBAR32(0x584) = 0xfffff;
4483 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484
4485 for (channel = 0; channel < NUM_CHANNELS; channel++)
4486 for (slot = 0; slot < NUM_SLOTS; slot++)
4487 for (rank = 0; rank < NUM_RANKS; rank++)
4488 if (info.
4489 populated_ranks[channel][slot]
4490 [rank])
4491 config_rank(&info, s3resume,
4492 channel, slot,
4493 rank);
4494
Felix Held04be2dd2018-07-29 04:53:22 +02004495 MCHBAR8(0x243) = 0x1;
4496 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004497 }
4498
4499 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004500 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004501 write_26c(0, 0x820);
4502 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004503 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 /* end */
4505
4506 if (s3resume) {
4507 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004508 MCHBAR32(0x294 + (channel << 10)) =
4509 (info.populated_ranks_mask[channel] & 3) << 16;
4510 MCHBAR16(0x298 + (channel << 10)) =
4511 info.populated_ranks[channel][0][0] |
4512 (info.populated_ranks[channel][0][1] << 5);
4513 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004514 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004515 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004516 }
4517
Felix Held04be2dd2018-07-29 04:53:22 +02004518 MCHBAR32_AND(0xfa4, ~0x01000002);
4519 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004521 /* Before training. */
4522 timestamp_add_now(103);
4523
4524 if (!s3resume)
4525 ram_training(&info);
4526
4527 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004528 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529
4530 dump_timings(&info);
4531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004532 program_modules_memory_map(&info, 0);
4533 program_total_memory_map(&info);
4534
4535 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004536 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004537 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004538 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004539 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004540 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 else
Felix Held04be2dd2018-07-29 04:53:22 +02004542 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543
Felix Held04be2dd2018-07-29 04:53:22 +02004544 MCHBAR32_AND(0xfac, ~0x80000000);
4545 MCHBAR32(0xfb4) = 0x4800;
4546 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4547 MCHBAR32(0xe94) = 0x7ffff;
4548 MCHBAR32(0xfc0) = 0x80002040;
4549 MCHBAR32(0xfc4) = 0x701246;
4550 MCHBAR8_AND(0xfc8, ~0x70);
4551 MCHBAR32_OR(0xe5c, 0x1000000);
4552 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4553 MCHBAR32(0x50) = 0x700b0;
4554 MCHBAR32(0x3c) = 0x10;
4555 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4556 MCHBAR8_OR(0xff4, 0x2);
4557 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558
Felix Held04be2dd2018-07-29 04:53:22 +02004559 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4560 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4561 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004562
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004563 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4564 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4565 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004567 {
4568 u32 eax;
4569
4570 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4572 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4573 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574 }
4575
4576 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 else
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584
Felix Held04be2dd2018-07-29 04:53:22 +02004585 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004588 else
Felix Held04be2dd2018-07-29 04:53:22 +02004589 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004590 }
4591
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593
4594 {
4595 u8 al;
4596 al = 0xd;
4597 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4598 al += 2;
4599 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004601 }
4602
4603 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004604 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4605 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4606 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4607 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004608 }
4609 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004610 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004611 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004612 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004613 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004614 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004615 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004616 MCHBAR8_OR(0x1210, 2);
4617 MCHBAR32(0x1200) = 0x8800440;
4618 MCHBAR32(0x1204) = 0x53ff0453;
4619 MCHBAR32(0x1208) = 0x19002043;
4620 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004621
4622 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004623 MCHBAR16(0x1214) = 0x220;
4624 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004625 }
4626
Felix Held04be2dd2018-07-29 04:53:22 +02004627 MCHBAR8_OR(0x1214, 0x4);
4628 MCHBAR8(0x120c) = 0x1;
4629 MCHBAR8(0x1218) = 0x3;
4630 MCHBAR8(0x121a) = 0x3;
4631 MCHBAR8(0x121c) = 0x3;
4632 MCHBAR16(0xc14) = 0x0;
4633 MCHBAR16(0xc20) = 0x0;
4634 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
4636 /* revision dependent here. */
4637
Felix Held04be2dd2018-07-29 04:53:22 +02004638 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639
4640 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642
Felix Held04be2dd2018-07-29 04:53:22 +02004643 MCHBAR16_OR(0x1230, 0x8000);
4644 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
4646 u8 bl, ebpb;
4647 u16 reg_1020;
4648
Felix Held04be2dd2018-07-29 04:53:22 +02004649 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4650 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR32(0x1000) = 0x100;
4653 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
4655 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657 bl = reg_1020 >> 8;
4658 ebpb = reg_1020 & 0xff;
4659 } else {
4660 ebpb = 0;
4661 bl = 8;
4662 }
4663
4664 rdmsr(0x1a2);
4665
Felix Held04be2dd2018-07-29 04:53:22 +02004666 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004667
Felix Held04be2dd2018-07-29 04:53:22 +02004668 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004669
Felix Held04be2dd2018-07-29 04:53:22 +02004670 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004671
Felix Held04be2dd2018-07-29 04:53:22 +02004672 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4675 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676 }
4677
4678 setup_heci_uma(&info);
4679
4680 if (info.uma_enabled) {
4681 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004682 MCHBAR32_OR(0x11b0, 0x4000);
4683 MCHBAR32_OR(0x11b4, 0x4000);
4684 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004685
Felix Held04be2dd2018-07-29 04:53:22 +02004686 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4687 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4688 MCHBAR16_OR(0x1170, 0x1000);
4689
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004691
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004693 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004694 ;
4695 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004696 }
4697
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004698 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4699 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004700 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004701 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004702
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703 udelay(1000);
4704 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004705 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4706
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707 if (!s3resume)
4708 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004709 if (s3resume && cbmem_wasnot_inited) {
4710 u32 reg32;
4711 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004712 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004713
4714 /* Clear SLP_TYPE. */
4715 reg32 = inl(DEFAULT_PMBASE + 0x04);
4716 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4717
4718 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004719 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004720 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721}