blob: 3908504832d16d1c63505d24e7e85a19c8db9915 [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
Angel Ponsb600d412021-01-16 16:33:48 +01001473 for (i = 0; i < 3; i++) {
1474 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1475 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1476 }
1477 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1478 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1479 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1480
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1482
1483 if ((capid0[1] >> 11) & 1)
1484 info->uma_enabled = 0;
1485 else
1486 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001487 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1489 info->silicon_revision = 0;
1490
1491 if (capid0[2] & 2) {
1492 info->silicon_revision = 0;
1493 info->max_supported_clock_speed_index = 2;
1494 for (channel = 0; channel < NUM_CHANNELS; channel++)
1495 if (info->populated_ranks[channel][0][0]
1496 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1497 3) {
1498 info->silicon_revision = 2;
1499 info->max_supported_clock_speed_index = 1;
1500 }
1501 } else {
1502 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1503 case 1:
1504 case 2:
1505 info->silicon_revision = 3;
1506 break;
1507 case 3:
1508 info->silicon_revision = 0;
1509 break;
1510 case 0:
1511 info->silicon_revision = 2;
1512 break;
1513 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001514 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001515 case 0x40:
1516 info->silicon_revision = 0;
1517 break;
1518 case 0x48:
1519 info->silicon_revision = 1;
1520 break;
1521 }
1522 }
1523}
1524
1525static void write_training_data(struct raminfo *info)
1526{
1527 int tm, channel, slot, rank, lane;
1528 if (info->revision < 8)
1529 return;
1530
1531 for (tm = 0; tm < 4; tm++)
1532 for (channel = 0; channel < NUM_CHANNELS; channel++)
1533 for (slot = 0; slot < NUM_SLOTS; slot++)
1534 for (rank = 0; rank < NUM_RANKS; rank++)
1535 for (lane = 0; lane < 9; lane++)
1536 write_500(info, channel,
1537 info->
1538 cached_training->
1539 lane_timings[tm]
1540 [channel][slot][rank]
1541 [lane],
1542 get_timing_register_addr
1543 (lane, tm, slot,
1544 rank), 9, 0);
1545 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1546 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1547}
1548
1549static void dump_timings(struct raminfo *info)
1550{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001551 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001552 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001553 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001554 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001555 slot, rank);
1556 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001557 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001558 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001559 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001560 read_500(info, channel,
1561 get_timing_register_addr
1562 (lane, i, slot, rank),
1563 9),
1564 info->training.
1565 lane_timings[i][channel][slot][rank]
1566 [lane]);
1567 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001568 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 }
1570 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575}
1576
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001577/* Read timings and other registers that need to be restored verbatim and
1578 put them to CBMEM.
1579 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580static void save_timings(struct raminfo *info)
1581{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 int channel, slot, rank, lane, i;
1584
1585 train = info->training;
1586 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1587 for (i = 0; i < 4; i++)
1588 train.lane_timings[i][channel][slot][rank][lane] =
1589 read_500(info, channel,
1590 get_timing_register_addr(lane, i, slot,
1591 rank), 9);
1592 train.reg_178 = read_1d0(0x178, 7);
1593 train.reg_10b = read_1d0(0x10b, 6);
1594
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1596 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001597 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001598 train.reg274265[channel][0] = reg32 >> 16;
1599 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001600 train.reg274265[channel][2] =
1601 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001602 }
Felix Held04be2dd2018-07-29 04:53:22 +02001603 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1604 train.reg_6dc = MCHBAR32(0x6dc);
1605 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001606
Arthur Heymansb3282092019-04-14 17:53:28 +02001607 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1608 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001609
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001611 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1612 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001613}
1614
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615static const struct ram_training *get_cached_training(void)
1616{
Shelley Chenad9cd682020-07-23 16:10:52 -07001617 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1618 MRC_CACHE_VERSION,
1619 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621
1622/* FIXME: add timeout. */
1623static void wait_heci_ready(void)
1624{
Felix Held04be2dd2018-07-29 04:53:22 +02001625 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1626 ;
Angel Ponseb537932020-09-14 19:18:11 +02001627
1628 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629}
1630
1631/* FIXME: add timeout. */
1632static void wait_heci_cb_avail(int len)
1633{
1634 union {
1635 struct mei_csr csr;
1636 u32 raw;
1637 } csr;
1638
Felix Held22ca8cb2018-07-29 05:09:44 +02001639 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1640 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641
Angel Ponseb537932020-09-14 19:18:11 +02001642 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001643 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001644 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1645 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646}
1647
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001648static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649{
1650 int len = (head->length + 3) / 4;
1651 int i;
1652
1653 wait_heci_cb_avail(len + 1);
1654
1655 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001656 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001657 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001658 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001660 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1661 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001662}
1663
Angel Ponseb537932020-09-14 19:18:11 +02001664static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665{
1666 struct mei_header head;
1667 int maxlen;
1668
1669 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001670 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671
1672 while (len) {
1673 int cur = len;
1674 if (cur > maxlen) {
1675 cur = maxlen;
1676 head.is_complete = 0;
1677 } else
1678 head.is_complete = 1;
1679 head.length = cur;
1680 head.reserved = 0;
1681 head.client_address = clientaddress;
1682 head.host_address = hostaddress;
1683 send_heci_packet(&head, (u32 *) msg);
1684 len -= cur;
1685 msg += cur;
1686 }
1687}
1688
1689/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001690static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001691{
1692 union {
1693 struct mei_csr csr;
1694 u32 raw;
1695 } csr;
1696 int i = 0;
1697
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001698 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001699 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001700 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001701 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1702
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001703 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001705 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001706 *packet_size = 0;
1707 return 0;
1708 }
Angel Ponseb537932020-09-14 19:18:11 +02001709 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710 *packet_size = 0;
1711 return -1;
1712 }
1713
Angel Ponseb537932020-09-14 19:18:11 +02001714 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001715 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001716 } while (((head->length + 3) >> 2) >
1717 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718
1719 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001720 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001721 *packet_size = head->length;
1722 if (!csr.csr.ready)
1723 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001724 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725 return 0;
1726}
1727
1728/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001729static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730{
1731 struct mei_header head;
1732 int current_position;
1733
1734 current_position = 0;
1735 while (1) {
1736 u32 current_size;
1737 current_size = *message_size - current_position;
1738 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001739 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740 &current_size) == -1)
1741 break;
1742 if (!current_size)
1743 break;
1744 current_position += current_size;
1745 if (head.is_complete) {
1746 *message_size = current_position;
1747 return 0;
1748 }
1749
1750 if (current_position >= *message_size)
1751 break;
1752 }
1753 *message_size = 0;
1754 return -1;
1755}
1756
Angel Pons55f11e22020-09-14 19:06:53 +02001757static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001758{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001759 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760 u8 group_id;
1761 u8 command;
1762 u8 reserved;
1763 u8 result;
1764 u8 field2;
1765 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001766 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001767
1768 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1769 reply.command = 0;
1770
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001771 struct uma_message {
1772 u8 group_id;
1773 u8 cmd;
1774 u8 reserved;
1775 u8 result;
1776 u32 c2;
1777 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001778 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001779 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001780 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001781 .group_id = 0,
1782 .cmd = MKHI_SET_UMA,
1783 .reserved = 0,
1784 .result = 0,
1785 .c2 = 0x82,
1786 .heci_uma_addr = heci_uma_addr,
1787 .heci_uma_size = heci_uma_size,
1788 .c3 = 0,
1789 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001790 u32 reply_size;
1791
Angel Ponseb537932020-09-14 19:18:11 +02001792 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001793
1794 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001795 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001796 return;
1797
1798 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1799 die("HECI init failed\n");
1800}
1801
1802static void setup_heci_uma(struct raminfo *info)
1803{
Angel Pons298d34d2020-09-14 18:58:53 +02001804 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001805 return;
1806
Angel Pons36592bf2020-09-14 18:52:44 +02001807 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001808 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001809 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001810 info->memory_reserved_for_heci_mb)) << 20;
1811
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001812 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001813 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001814 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001815 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001816 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001817 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001818 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001819 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001820 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001821 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001822
Angel Ponsee7fb342021-01-28 14:11:55 +01001823 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001824 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001825
Angel Ponsee7fb342021-01-28 14:11:55 +01001826 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001827 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828 }
1829
Felix Held04be2dd2018-07-29 04:53:22 +02001830 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831
Angel Pons55f11e22020-09-14 19:06:53 +02001832 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001834 pci_write_config32(HECIDEV, 0x10, 0x0);
1835 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836}
1837
1838static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1839{
1840 int ranks_in_channel;
1841 ranks_in_channel = info->populated_ranks[channel][0][0]
1842 + info->populated_ranks[channel][0][1]
1843 + info->populated_ranks[channel][1][0]
1844 + info->populated_ranks[channel][1][1];
1845
1846 /* empty channel */
1847 if (ranks_in_channel == 0)
1848 return 1;
1849
1850 if (ranks_in_channel != ranks)
1851 return 0;
1852 /* single slot */
1853 if (info->populated_ranks[channel][0][0] !=
1854 info->populated_ranks[channel][1][0])
1855 return 1;
1856 if (info->populated_ranks[channel][0][1] !=
1857 info->populated_ranks[channel][1][1])
1858 return 1;
1859 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1860 return 0;
1861 if (info->density[channel][0] != info->density[channel][1])
1862 return 0;
1863 return 1;
1864}
1865
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866static void read_4090(struct raminfo *info)
1867{
1868 int i, channel, slot, rank, lane;
1869 for (i = 0; i < 2; i++)
1870 for (slot = 0; slot < NUM_SLOTS; slot++)
1871 for (rank = 0; rank < NUM_RANKS; rank++)
1872 for (lane = 0; lane < 9; lane++)
1873 info->training.
1874 lane_timings[0][i][slot][rank][lane]
1875 = 32;
1876
1877 for (i = 1; i < 4; i++)
1878 for (channel = 0; channel < NUM_CHANNELS; channel++)
1879 for (slot = 0; slot < NUM_SLOTS; slot++)
1880 for (rank = 0; rank < NUM_RANKS; rank++)
1881 for (lane = 0; lane < 9; lane++) {
1882 info->training.
1883 lane_timings[i][channel]
1884 [slot][rank][lane] =
1885 read_500(info, channel,
1886 get_timing_register_addr
1887 (lane, i, slot,
1888 rank), 9)
1889 + (i == 1) * 11; // !!!!
1890 }
1891
1892}
1893
1894static u32 get_etalon2(int flip, u32 addr)
1895{
1896 const u16 invmask[] = {
1897 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1898 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1899 };
1900 u32 ret;
1901 u32 comp4 = addr / 480;
1902 addr %= 480;
1903 u32 comp1 = addr & 0xf;
1904 u32 comp2 = (addr >> 4) & 1;
1905 u32 comp3 = addr >> 5;
1906
1907 if (comp4)
1908 ret = 0x1010101 << (comp4 - 1);
1909 else
1910 ret = 0;
1911 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1912 ret = ~ret;
1913
1914 return ret;
1915}
1916
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001917static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001918{
1919 msr_t msr = {.lo = 0, .hi = 0 };
1920
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001921 wrmsr(MTRR_PHYS_BASE(3), msr);
1922 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001923}
1924
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001925static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001926{
1927 msr_t msr;
1928 msr.lo = base | MTRR_TYPE_WRPROT;
1929 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001930 wrmsr(MTRR_PHYS_BASE(3), msr);
1931 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001932 & 0xffffffff);
1933 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001934 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001935}
1936
1937static void flush_cache(u32 start, u32 size)
1938{
1939 u32 end;
1940 u32 addr;
1941
1942 end = start + (ALIGN_DOWN(size + 4096, 4096));
1943 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001944 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945}
1946
1947static void clear_errors(void)
1948{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001949 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001950}
1951
1952static void write_testing(struct raminfo *info, int totalrank, int flip)
1953{
1954 int nwrites = 0;
1955 /* in 8-byte units. */
1956 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001957 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958
Patrick Rudolph819c2062019-11-29 19:27:37 +01001959 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001960 for (offset = 0; offset < 9 * 480; offset += 2) {
1961 write32(base + offset * 8, get_etalon2(flip, offset));
1962 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1963 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1964 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1965 nwrites += 4;
1966 if (nwrites >= 320) {
1967 clear_errors();
1968 nwrites = 0;
1969 }
1970 }
1971}
1972
1973static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1974{
1975 u8 failmask = 0;
1976 int i;
1977 int comp1, comp2, comp3;
1978 u32 failxor[2] = { 0, 0 };
1979
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001980 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001981
1982 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1983 for (comp1 = 0; comp1 < 4; comp1++)
1984 for (comp2 = 0; comp2 < 60; comp2++) {
1985 u32 re[4];
1986 u32 curroffset =
1987 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1988 read128((total_rank << 28) | (curroffset << 3),
1989 (u64 *) re);
1990 failxor[0] |=
1991 get_etalon2(flip, curroffset) ^ re[0];
1992 failxor[1] |=
1993 get_etalon2(flip, curroffset) ^ re[1];
1994 failxor[0] |=
1995 get_etalon2(flip, curroffset | 1) ^ re[2];
1996 failxor[1] |=
1997 get_etalon2(flip, curroffset | 1) ^ re[3];
1998 }
1999 for (i = 0; i < 8; i++)
2000 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2001 failmask |= 1 << i;
2002 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002003 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002004 flush_cache((total_rank << 28), 1728 * 5 * 4);
2005 return failmask;
2006}
2007
2008const u32 seed1[0x18] = {
2009 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2010 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2011 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2012 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2013 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2014 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2015};
2016
2017static u32 get_seed2(int a, int b)
2018{
2019 const u32 seed2[5] = {
2020 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2021 0x5b6db6db,
2022 };
2023 u32 r;
2024 r = seed2[(a + (a >= 10)) / 5];
2025 return b ? ~r : r;
2026}
2027
2028static int make_shift(int comp2, int comp5, int x)
2029{
2030 const u8 seed3[32] = {
2031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2032 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2033 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2034 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2035 };
2036
2037 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2038}
2039
2040static u32 get_etalon(int flip, u32 addr)
2041{
2042 u32 mask_byte = 0;
2043 int comp1 = (addr >> 1) & 1;
2044 int comp2 = (addr >> 3) & 0x1f;
2045 int comp3 = (addr >> 8) & 0xf;
2046 int comp4 = (addr >> 12) & 0xf;
2047 int comp5 = (addr >> 16) & 0x1f;
2048 u32 mask_bit = ~(0x10001 << comp3);
2049 u32 part1;
2050 u32 part2;
2051 int byte;
2052
2053 part2 =
2054 ((seed1[comp5] >>
2055 make_shift(comp2, comp5,
2056 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2057 part1 =
2058 ((seed1[comp5] >>
2059 make_shift(comp2, comp5,
2060 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2061
2062 for (byte = 0; byte < 4; byte++)
2063 if ((get_seed2(comp5, comp4) >>
2064 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2065 mask_byte |= 0xff << (8 * byte);
2066
2067 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2068 (comp3 + 16));
2069}
2070
2071static void
2072write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2073 char flip)
2074{
2075 int i;
2076 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002077 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2078 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002079}
2080
2081static u8
2082check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2083 char flip)
2084{
2085 u8 failmask = 0;
2086 u32 failxor[2];
2087 int i;
2088 int comp1, comp2, comp3;
2089
2090 failxor[0] = 0;
2091 failxor[1] = 0;
2092
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002093 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002094 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2095 for (comp1 = 0; comp1 < 16; comp1++)
2096 for (comp2 = 0; comp2 < 64; comp2++) {
2097 u32 addr =
2098 (totalrank << 28) | (region << 25) | (block
2099 << 16)
2100 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2101 2);
2102 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002103 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002104 }
2105 for (i = 0; i < 8; i++)
2106 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2107 failmask |= 1 << i;
2108 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002109 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002110 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2111 return failmask;
2112}
2113
2114static int check_bounded(unsigned short *vals, u16 bound)
2115{
2116 int i;
2117
2118 for (i = 0; i < 8; i++)
2119 if (vals[i] < bound)
2120 return 0;
2121 return 1;
2122}
2123
2124enum state {
2125 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2126};
2127
2128static int validate_state(enum state *in)
2129{
2130 int i;
2131 for (i = 0; i < 8; i++)
2132 if (in[i] != COMPLETE)
2133 return 0;
2134 return 1;
2135}
2136
2137static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002138do_fsm(enum state *state, u16 *counter,
2139 u8 fail_mask, int margin, int uplimit,
2140 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002141{
2142 int lane;
2143
2144 for (lane = 0; lane < 8; lane++) {
2145 int is_fail = (fail_mask >> lane) & 1;
2146 switch (state[lane]) {
2147 case BEFORE_USABLE:
2148 if (!is_fail) {
2149 counter[lane] = 1;
2150 state[lane] = AT_USABLE;
2151 break;
2152 }
2153 counter[lane] = 0;
2154 state[lane] = BEFORE_USABLE;
2155 break;
2156 case AT_USABLE:
2157 if (!is_fail) {
2158 ++counter[lane];
2159 if (counter[lane] >= margin) {
2160 state[lane] = AT_MARGIN;
2161 res_low[lane] = val - margin + 1;
2162 break;
2163 }
2164 state[lane] = 1;
2165 break;
2166 }
2167 counter[lane] = 0;
2168 state[lane] = BEFORE_USABLE;
2169 break;
2170 case AT_MARGIN:
2171 if (is_fail) {
2172 state[lane] = COMPLETE;
2173 res_high[lane] = val - 1;
2174 } else {
2175 counter[lane]++;
2176 state[lane] = AT_MARGIN;
2177 if (val == uplimit) {
2178 state[lane] = COMPLETE;
2179 res_high[lane] = uplimit;
2180 }
2181 }
2182 break;
2183 case COMPLETE:
2184 break;
2185 }
2186 }
2187}
2188
2189static void
2190train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2191 u8 total_rank, u8 reg_178, int first_run, int niter,
2192 timing_bounds_t * timings)
2193{
2194 int lane;
2195 enum state state[8];
2196 u16 count[8];
2197 u8 lower_usable[8];
2198 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002199 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002200 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002201 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002202
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002203 for (i = 0; i < 8; i++)
2204 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002205
2206 if (!first_run) {
2207 int is_all_ok = 1;
2208 for (lane = 0; lane < 8; lane++)
2209 if (timings[reg_178][channel][slot][rank][lane].
2210 smallest ==
2211 timings[reg_178][channel][slot][rank][lane].
2212 largest) {
2213 timings[reg_178][channel][slot][rank][lane].
2214 smallest = 0;
2215 timings[reg_178][channel][slot][rank][lane].
2216 largest = 0;
2217 is_all_ok = 0;
2218 }
2219 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002220 for (i = 0; i < 8; i++)
2221 state[i] = COMPLETE;
2222 }
2223 }
2224
2225 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2226 u8 failmask = 0;
2227 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2228 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2229 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002230 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002231 do_fsm(state, count, failmask, 5, 47, lower_usable,
2232 upper_usable, reg1b3);
2233 }
2234
2235 if (reg1b3) {
2236 write_1d0(0, 0x1b3, 6, 1);
2237 write_1d0(0, 0x1a3, 6, 1);
2238 for (lane = 0; lane < 8; lane++) {
2239 if (state[lane] == COMPLETE) {
2240 timings[reg_178][channel][slot][rank][lane].
2241 smallest =
2242 lower_usable[lane] +
2243 (info->training.
2244 lane_timings[0][channel][slot][rank][lane]
2245 & 0x3F) - 32;
2246 timings[reg_178][channel][slot][rank][lane].
2247 largest =
2248 upper_usable[lane] +
2249 (info->training.
2250 lane_timings[0][channel][slot][rank][lane]
2251 & 0x3F) - 32;
2252 }
2253 }
2254 }
2255
2256 if (!first_run) {
2257 for (lane = 0; lane < 8; lane++)
2258 if (state[lane] == COMPLETE) {
2259 write_500(info, channel,
2260 timings[reg_178][channel][slot][rank]
2261 [lane].smallest,
2262 get_timing_register_addr(lane, 0,
2263 slot, rank),
2264 9, 1);
2265 write_500(info, channel,
2266 timings[reg_178][channel][slot][rank]
2267 [lane].smallest +
2268 info->training.
2269 lane_timings[1][channel][slot][rank]
2270 [lane]
2271 -
2272 info->training.
2273 lane_timings[0][channel][slot][rank]
2274 [lane], get_timing_register_addr(lane,
2275 1,
2276 slot,
2277 rank),
2278 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002279 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002280 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002281 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002282
2283 do {
2284 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002285 for (i = 0; i < niter; i++) {
2286 if (failmask == 0xFF)
2287 break;
2288 failmask |=
2289 check_testing_type2(info, total_rank, 2, i,
2290 0);
2291 failmask |=
2292 check_testing_type2(info, total_rank, 3, i,
2293 1);
2294 }
Felix Held04be2dd2018-07-29 04:53:22 +02002295 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002297 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002298 if ((1 << lane) & failmask) {
2299 if (timings[reg_178][channel]
2300 [slot][rank][lane].
2301 largest <=
2302 timings[reg_178][channel]
2303 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002304 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002305 [lane] = -1;
2306 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002307 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308 [lane] = 0;
2309 timings[reg_178]
2310 [channel][slot]
2311 [rank][lane].
2312 smallest++;
2313 write_500(info, channel,
2314 timings
2315 [reg_178]
2316 [channel]
2317 [slot][rank]
2318 [lane].
2319 smallest,
2320 get_timing_register_addr
2321 (lane, 0,
2322 slot, rank),
2323 9, 1);
2324 write_500(info, channel,
2325 timings
2326 [reg_178]
2327 [channel]
2328 [slot][rank]
2329 [lane].
2330 smallest +
2331 info->
2332 training.
2333 lane_timings
2334 [1][channel]
2335 [slot][rank]
2336 [lane]
2337 -
2338 info->
2339 training.
2340 lane_timings
2341 [0][channel]
2342 [slot][rank]
2343 [lane],
2344 get_timing_register_addr
2345 (lane, 1,
2346 slot, rank),
2347 9, 1);
2348 }
2349 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002350 num_successfully_checked[lane]
2351 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002352 }
2353 }
Felix Held04be2dd2018-07-29 04:53:22 +02002354 while (!check_bounded(num_successfully_checked, 2))
2355 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002356
2357 for (lane = 0; lane < 8; lane++)
2358 if (state[lane] == COMPLETE) {
2359 write_500(info, channel,
2360 timings[reg_178][channel][slot][rank]
2361 [lane].largest,
2362 get_timing_register_addr(lane, 0,
2363 slot, rank),
2364 9, 1);
2365 write_500(info, channel,
2366 timings[reg_178][channel][slot][rank]
2367 [lane].largest +
2368 info->training.
2369 lane_timings[1][channel][slot][rank]
2370 [lane]
2371 -
2372 info->training.
2373 lane_timings[0][channel][slot][rank]
2374 [lane], get_timing_register_addr(lane,
2375 1,
2376 slot,
2377 rank),
2378 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002379 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002381 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002382
2383 do {
2384 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002385 for (i = 0; i < niter; i++) {
2386 if (failmask == 0xFF)
2387 break;
2388 failmask |=
2389 check_testing_type2(info, total_rank, 2, i,
2390 0);
2391 failmask |=
2392 check_testing_type2(info, total_rank, 3, i,
2393 1);
2394 }
2395
Felix Held04be2dd2018-07-29 04:53:22 +02002396 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002398 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399 if ((1 << lane) & failmask) {
2400 if (timings[reg_178][channel]
2401 [slot][rank][lane].
2402 largest <=
2403 timings[reg_178][channel]
2404 [slot][rank][lane].
2405 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002406 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002407 [lane] = -1;
2408 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002409 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002410 [lane] = 0;
2411 timings[reg_178]
2412 [channel][slot]
2413 [rank][lane].
2414 largest--;
2415 write_500(info, channel,
2416 timings
2417 [reg_178]
2418 [channel]
2419 [slot][rank]
2420 [lane].
2421 largest,
2422 get_timing_register_addr
2423 (lane, 0,
2424 slot, rank),
2425 9, 1);
2426 write_500(info, channel,
2427 timings
2428 [reg_178]
2429 [channel]
2430 [slot][rank]
2431 [lane].
2432 largest +
2433 info->
2434 training.
2435 lane_timings
2436 [1][channel]
2437 [slot][rank]
2438 [lane]
2439 -
2440 info->
2441 training.
2442 lane_timings
2443 [0][channel]
2444 [slot][rank]
2445 [lane],
2446 get_timing_register_addr
2447 (lane, 1,
2448 slot, rank),
2449 9, 1);
2450 }
2451 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002452 num_successfully_checked[lane]
2453 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002454 }
2455 }
2456 }
Felix Held04be2dd2018-07-29 04:53:22 +02002457 while (!check_bounded(num_successfully_checked, 3))
2458 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002459
2460 for (lane = 0; lane < 8; lane++) {
2461 write_500(info, channel,
2462 info->training.
2463 lane_timings[0][channel][slot][rank][lane],
2464 get_timing_register_addr(lane, 0, slot, rank),
2465 9, 1);
2466 write_500(info, channel,
2467 info->training.
2468 lane_timings[1][channel][slot][rank][lane],
2469 get_timing_register_addr(lane, 1, slot, rank),
2470 9, 1);
2471 if (timings[reg_178][channel][slot][rank][lane].
2472 largest <=
2473 timings[reg_178][channel][slot][rank][lane].
2474 smallest) {
2475 timings[reg_178][channel][slot][rank][lane].
2476 largest = 0;
2477 timings[reg_178][channel][slot][rank][lane].
2478 smallest = 0;
2479 }
2480 }
2481 }
2482}
2483
2484static void set_10b(struct raminfo *info, u8 val)
2485{
2486 int channel;
2487 int slot, rank;
2488 int lane;
2489
2490 if (read_1d0(0x10b, 6) == val)
2491 return;
2492
2493 write_1d0(val, 0x10b, 6, 1);
2494
2495 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2496 u16 reg_500;
2497 reg_500 = read_500(info, channel,
2498 get_timing_register_addr(lane, 0, slot,
2499 rank), 9);
2500 if (val == 1) {
2501 if (lut16[info->clock_speed_index] <= reg_500)
2502 reg_500 -= lut16[info->clock_speed_index];
2503 else
2504 reg_500 = 0;
2505 } else {
2506 reg_500 += lut16[info->clock_speed_index];
2507 }
2508 write_500(info, channel, reg_500,
2509 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2510 }
2511}
2512
2513static void set_ecc(int onoff)
2514{
2515 int channel;
2516 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2517 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002518 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002519 if (onoff)
2520 t |= 1;
2521 else
2522 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002523 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002524 }
2525}
2526
2527static void set_178(u8 val)
2528{
2529 if (val >= 31)
2530 val = val - 31;
2531 else
2532 val = 63 - val;
2533
2534 write_1d0(2 * val, 0x178, 7, 1);
2535}
2536
2537static void
2538write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2539 int type)
2540{
2541 int lane;
2542
2543 for (lane = 0; lane < 8; lane++)
2544 write_500(info, channel,
2545 info->training.
2546 lane_timings[type][channel][slot][rank][lane],
2547 get_timing_register_addr(lane, type, slot, rank), 9,
2548 0);
2549}
2550
2551static void
2552try_timing_offsets(struct raminfo *info, int channel,
2553 int slot, int rank, int totalrank)
2554{
2555 u16 count[8];
2556 enum state state[8];
2557 u8 lower_usable[8], upper_usable[8];
2558 int lane;
2559 int i;
2560 int flip = 1;
2561 int timing_offset;
2562
2563 for (i = 0; i < 8; i++)
2564 state[i] = BEFORE_USABLE;
2565
2566 memset(count, 0, sizeof(count));
2567
2568 for (lane = 0; lane < 8; lane++)
2569 write_500(info, channel,
2570 info->training.
2571 lane_timings[2][channel][slot][rank][lane] + 32,
2572 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2573
2574 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2575 timing_offset++) {
2576 u8 failmask;
2577 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2578 failmask = 0;
2579 for (i = 0; i < 2 && failmask != 0xff; i++) {
2580 flip = !flip;
2581 write_testing(info, totalrank, flip);
2582 failmask |= check_testing(info, totalrank, flip);
2583 }
2584 do_fsm(state, count, failmask, 10, 63, lower_usable,
2585 upper_usable, timing_offset);
2586 }
2587 write_1d0(0, 0x1bb, 6, 1);
2588 dump_timings(info);
2589 if (!validate_state(state))
2590 die("Couldn't discover DRAM timings (1)\n");
2591
2592 for (lane = 0; lane < 8; lane++) {
2593 u8 bias = 0;
2594
2595 if (info->silicon_revision) {
2596 int usable_length;
2597
2598 usable_length = upper_usable[lane] - lower_usable[lane];
2599 if (usable_length >= 20) {
2600 bias = usable_length / 2 - 10;
2601 if (bias >= 2)
2602 bias = 2;
2603 }
2604 }
2605 write_500(info, channel,
2606 info->training.
2607 lane_timings[2][channel][slot][rank][lane] +
2608 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2609 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2610 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2611 info->training.lane_timings[2][channel][slot][rank][lane] +
2612 lower_usable[lane];
2613 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2614 info->training.lane_timings[2][channel][slot][rank][lane] +
2615 upper_usable[lane];
2616 info->training.timing2_offset[channel][slot][rank][lane] =
2617 info->training.lane_timings[2][channel][slot][rank][lane];
2618 }
2619}
2620
2621static u8
2622choose_training(struct raminfo *info, int channel, int slot, int rank,
2623 int lane, timing_bounds_t * timings, u8 center_178)
2624{
2625 u16 central_weight;
2626 u16 side_weight;
2627 unsigned int sum = 0, count = 0;
2628 u8 span;
2629 u8 lower_margin, upper_margin;
2630 u8 reg_178;
2631 u8 result;
2632
2633 span = 12;
2634 central_weight = 20;
2635 side_weight = 20;
2636 if (info->silicon_revision == 1 && channel == 1) {
2637 central_weight = 5;
2638 side_weight = 20;
2639 if ((info->
2640 populated_ranks_mask[1] ^ (info->
2641 populated_ranks_mask[1] >> 2)) &
2642 1)
2643 span = 18;
2644 }
2645 if ((info->populated_ranks_mask[0] & 5) == 5) {
2646 central_weight = 20;
2647 side_weight = 20;
2648 }
2649 if (info->clock_speed_index >= 2
2650 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2651 if (info->silicon_revision == 1) {
2652 switch (channel) {
2653 case 0:
2654 if (lane == 1) {
2655 central_weight = 10;
2656 side_weight = 20;
2657 }
2658 break;
2659 case 1:
2660 if (lane == 6) {
2661 side_weight = 5;
2662 central_weight = 20;
2663 }
2664 break;
2665 }
2666 }
2667 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2668 side_weight = 5;
2669 central_weight = 20;
2670 }
2671 }
2672 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2673 reg_178 += span) {
2674 u8 smallest;
2675 u8 largest;
2676 largest = timings[reg_178][channel][slot][rank][lane].largest;
2677 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2678 if (largest - smallest + 1 >= 5) {
2679 unsigned int weight;
2680 if (reg_178 == center_178)
2681 weight = central_weight;
2682 else
2683 weight = side_weight;
2684 sum += weight * (largest + smallest);
2685 count += weight;
2686 }
2687 }
2688 dump_timings(info);
2689 if (count == 0)
2690 die("Couldn't discover DRAM timings (2)\n");
2691 result = sum / (2 * count);
2692 lower_margin =
2693 result - timings[center_178][channel][slot][rank][lane].smallest;
2694 upper_margin =
2695 timings[center_178][channel][slot][rank][lane].largest - result;
2696 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002697 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002698 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002699 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002700 return result;
2701}
2702
2703#define STANDARD_MIN_MARGIN 5
2704
2705static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2706{
2707 u16 margin[64];
2708 int lane, rank, slot, channel;
2709 u8 reg178;
2710 int count = 0, sum = 0;
2711
2712 for (reg178 = reg178_min[info->clock_speed_index];
2713 reg178 < reg178_max[info->clock_speed_index];
2714 reg178 += reg178_step[info->clock_speed_index]) {
2715 margin[reg178] = -1;
2716 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2717 int curmargin =
2718 timings[reg178][channel][slot][rank][lane].largest -
2719 timings[reg178][channel][slot][rank][lane].
2720 smallest + 1;
2721 if (curmargin < margin[reg178])
2722 margin[reg178] = curmargin;
2723 }
2724 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2725 u16 weight;
2726 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2727 sum += weight * reg178;
2728 count += weight;
2729 }
2730 }
2731 dump_timings(info);
2732 if (count == 0)
2733 die("Couldn't discover DRAM timings (3)\n");
2734
2735 u8 threshold;
2736
2737 for (threshold = 30; threshold >= 5; threshold--) {
2738 int usable_length = 0;
2739 int smallest_fount = 0;
2740 for (reg178 = reg178_min[info->clock_speed_index];
2741 reg178 < reg178_max[info->clock_speed_index];
2742 reg178 += reg178_step[info->clock_speed_index])
2743 if (margin[reg178] >= threshold) {
2744 usable_length +=
2745 reg178_step[info->clock_speed_index];
2746 info->training.reg178_largest =
2747 reg178 -
2748 2 * reg178_step[info->clock_speed_index];
2749
2750 if (!smallest_fount) {
2751 smallest_fount = 1;
2752 info->training.reg178_smallest =
2753 reg178 +
2754 reg178_step[info->
2755 clock_speed_index];
2756 }
2757 }
2758 if (usable_length >= 0x21)
2759 break;
2760 }
2761
2762 return sum / count;
2763}
2764
2765static int check_cached_sanity(struct raminfo *info)
2766{
2767 int lane;
2768 int slot, rank;
2769 int channel;
2770
2771 if (!info->cached_training)
2772 return 0;
2773
2774 for (channel = 0; channel < NUM_CHANNELS; channel++)
2775 for (slot = 0; slot < NUM_SLOTS; slot++)
2776 for (rank = 0; rank < NUM_RANKS; rank++)
2777 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2778 u16 cached_value, estimation_value;
2779 cached_value =
2780 info->cached_training->
2781 lane_timings[1][channel][slot][rank]
2782 [lane];
2783 if (cached_value >= 0x18
2784 && cached_value <= 0x1E7) {
2785 estimation_value =
2786 info->training.
2787 lane_timings[1][channel]
2788 [slot][rank][lane];
2789 if (estimation_value <
2790 cached_value - 24)
2791 return 0;
2792 if (estimation_value >
2793 cached_value + 24)
2794 return 0;
2795 }
2796 }
2797 return 1;
2798}
2799
2800static int try_cached_training(struct raminfo *info)
2801{
2802 u8 saved_243[2];
2803 u8 tm;
2804
2805 int channel, slot, rank, lane;
2806 int flip = 1;
2807 int i, j;
2808
2809 if (!check_cached_sanity(info))
2810 return 0;
2811
2812 info->training.reg178_center = info->cached_training->reg178_center;
2813 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2814 info->training.reg178_largest = info->cached_training->reg178_largest;
2815 memcpy(&info->training.timing_bounds,
2816 &info->cached_training->timing_bounds,
2817 sizeof(info->training.timing_bounds));
2818 memcpy(&info->training.timing_offset,
2819 &info->cached_training->timing_offset,
2820 sizeof(info->training.timing_offset));
2821
2822 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002823 saved_243[0] = MCHBAR8(0x243);
2824 saved_243[1] = MCHBAR8(0x643);
2825 MCHBAR8(0x243) = saved_243[0] | 2;
2826 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002827 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002828 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002829 if (read_1d0(0x10b, 6) & 1)
2830 set_10b(info, 0);
2831 for (tm = 0; tm < 2; tm++) {
2832 int totalrank;
2833
2834 set_178(tm ? info->cached_training->reg178_largest : info->
2835 cached_training->reg178_smallest);
2836
2837 totalrank = 0;
2838 /* Check timing ranges. With i == 0 we check smallest one and with
2839 i == 1 the largest bound. With j == 0 we check that on the bound
2840 it still works whereas with j == 1 we check that just outside of
2841 bound we fail.
2842 */
2843 FOR_POPULATED_RANKS_BACKWARDS {
2844 for (i = 0; i < 2; i++) {
2845 for (lane = 0; lane < 8; lane++) {
2846 write_500(info, channel,
2847 info->cached_training->
2848 timing2_bounds[channel][slot]
2849 [rank][lane][i],
2850 get_timing_register_addr(lane,
2851 3,
2852 slot,
2853 rank),
2854 9, 1);
2855
2856 if (!i)
2857 write_500(info, channel,
2858 info->
2859 cached_training->
2860 timing2_offset
2861 [channel][slot][rank]
2862 [lane],
2863 get_timing_register_addr
2864 (lane, 2, slot, rank),
2865 9, 1);
2866 write_500(info, channel,
2867 i ? info->cached_training->
2868 timing_bounds[tm][channel]
2869 [slot][rank][lane].
2870 largest : info->
2871 cached_training->
2872 timing_bounds[tm][channel]
2873 [slot][rank][lane].smallest,
2874 get_timing_register_addr(lane,
2875 0,
2876 slot,
2877 rank),
2878 9, 1);
2879 write_500(info, channel,
2880 info->cached_training->
2881 timing_offset[channel][slot]
2882 [rank][lane] +
2883 (i ? info->cached_training->
2884 timing_bounds[tm][channel]
2885 [slot][rank][lane].
2886 largest : info->
2887 cached_training->
2888 timing_bounds[tm][channel]
2889 [slot][rank][lane].
2890 smallest) - 64,
2891 get_timing_register_addr(lane,
2892 1,
2893 slot,
2894 rank),
2895 9, 1);
2896 }
2897 for (j = 0; j < 2; j++) {
2898 u8 failmask;
2899 u8 expected_failmask;
2900 char reg1b3;
2901
2902 reg1b3 = (j == 1) + 4;
2903 reg1b3 =
2904 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2905 write_1d0(reg1b3, 0x1bb, 6, 1);
2906 write_1d0(reg1b3, 0x1b3, 6, 1);
2907 write_1d0(reg1b3, 0x1a3, 6, 1);
2908
2909 flip = !flip;
2910 write_testing(info, totalrank, flip);
2911 failmask =
2912 check_testing(info, totalrank,
2913 flip);
2914 expected_failmask =
2915 j == 0 ? 0x00 : 0xff;
2916 if (failmask != expected_failmask)
2917 goto fail;
2918 }
2919 }
2920 totalrank++;
2921 }
2922 }
2923
2924 set_178(info->cached_training->reg178_center);
2925 if (info->use_ecc)
2926 set_ecc(1);
2927 write_training_data(info);
2928 write_1d0(0, 322, 3, 1);
2929 info->training = *info->cached_training;
2930
2931 write_1d0(0, 0x1bb, 6, 1);
2932 write_1d0(0, 0x1b3, 6, 1);
2933 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002934 MCHBAR8(0x243) = saved_243[0];
2935 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002936
2937 return 1;
2938
2939fail:
2940 FOR_POPULATED_RANKS {
2941 write_500_timings_type(info, channel, slot, rank, 1);
2942 write_500_timings_type(info, channel, slot, rank, 2);
2943 write_500_timings_type(info, channel, slot, rank, 3);
2944 }
2945
2946 write_1d0(0, 0x1bb, 6, 1);
2947 write_1d0(0, 0x1b3, 6, 1);
2948 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002949 MCHBAR8(0x243) = saved_243[0];
2950 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002951
2952 return 0;
2953}
2954
2955static void do_ram_training(struct raminfo *info)
2956{
2957 u8 saved_243[2];
2958 int totalrank = 0;
2959 u8 reg_178;
2960 int niter;
2961
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002962 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002963 int lane, rank, slot, channel;
2964 u8 reg178_center;
2965
2966 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002967 saved_243[0] = MCHBAR8(0x243);
2968 saved_243[1] = MCHBAR8(0x643);
2969 MCHBAR8(0x243) = saved_243[0] | 2;
2970 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002971 switch (info->clock_speed_index) {
2972 case 0:
2973 niter = 5;
2974 break;
2975 case 1:
2976 niter = 10;
2977 break;
2978 default:
2979 niter = 19;
2980 break;
2981 }
2982 set_ecc(0);
2983
2984 FOR_POPULATED_RANKS_BACKWARDS {
2985 int i;
2986
2987 write_500_timings_type(info, channel, slot, rank, 0);
2988
2989 write_testing(info, totalrank, 0);
2990 for (i = 0; i < niter; i++) {
2991 write_testing_type2(info, totalrank, 2, i, 0);
2992 write_testing_type2(info, totalrank, 3, i, 1);
2993 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002994 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002995 totalrank++;
2996 }
2997
2998 if (reg178_min[info->clock_speed_index] <
2999 reg178_max[info->clock_speed_index])
3000 memset(timings[reg178_min[info->clock_speed_index]], 0,
3001 sizeof(timings[0]) *
3002 (reg178_max[info->clock_speed_index] -
3003 reg178_min[info->clock_speed_index]));
3004 for (reg_178 = reg178_min[info->clock_speed_index];
3005 reg_178 < reg178_max[info->clock_speed_index];
3006 reg_178 += reg178_step[info->clock_speed_index]) {
3007 totalrank = 0;
3008 set_178(reg_178);
3009 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3010 for (slot = 0; slot < NUM_SLOTS; slot++)
3011 for (rank = 0; rank < NUM_RANKS; rank++) {
3012 memset(&timings[reg_178][channel][slot]
3013 [rank][0].smallest, 0, 16);
3014 if (info->
3015 populated_ranks[channel][slot]
3016 [rank]) {
3017 train_ram_at_178(info, channel,
3018 slot, rank,
3019 totalrank,
3020 reg_178, 1,
3021 niter,
3022 timings);
3023 totalrank++;
3024 }
3025 }
3026 }
3027
3028 reg178_center = choose_reg178(info, timings);
3029
3030 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3031 info->training.timing_bounds[0][channel][slot][rank][lane].
3032 smallest =
3033 timings[info->training.
3034 reg178_smallest][channel][slot][rank][lane].
3035 smallest;
3036 info->training.timing_bounds[0][channel][slot][rank][lane].
3037 largest =
3038 timings[info->training.
3039 reg178_smallest][channel][slot][rank][lane].largest;
3040 info->training.timing_bounds[1][channel][slot][rank][lane].
3041 smallest =
3042 timings[info->training.
3043 reg178_largest][channel][slot][rank][lane].smallest;
3044 info->training.timing_bounds[1][channel][slot][rank][lane].
3045 largest =
3046 timings[info->training.
3047 reg178_largest][channel][slot][rank][lane].largest;
3048 info->training.timing_offset[channel][slot][rank][lane] =
3049 info->training.lane_timings[1][channel][slot][rank][lane]
3050 -
3051 info->training.lane_timings[0][channel][slot][rank][lane] +
3052 64;
3053 }
3054
3055 if (info->silicon_revision == 1
3056 && (info->
3057 populated_ranks_mask[1] ^ (info->
3058 populated_ranks_mask[1] >> 2)) & 1) {
3059 int ranks_after_channel1;
3060
3061 totalrank = 0;
3062 for (reg_178 = reg178_center - 18;
3063 reg_178 <= reg178_center + 18; reg_178 += 18) {
3064 totalrank = 0;
3065 set_178(reg_178);
3066 for (slot = 0; slot < NUM_SLOTS; slot++)
3067 for (rank = 0; rank < NUM_RANKS; rank++) {
3068 if (info->
3069 populated_ranks[1][slot][rank]) {
3070 train_ram_at_178(info, 1, slot,
3071 rank,
3072 totalrank,
3073 reg_178, 0,
3074 niter,
3075 timings);
3076 totalrank++;
3077 }
3078 }
3079 }
3080 ranks_after_channel1 = totalrank;
3081
3082 for (reg_178 = reg178_center - 12;
3083 reg_178 <= reg178_center + 12; reg_178 += 12) {
3084 totalrank = ranks_after_channel1;
3085 set_178(reg_178);
3086 for (slot = 0; slot < NUM_SLOTS; slot++)
3087 for (rank = 0; rank < NUM_RANKS; rank++)
3088 if (info->
3089 populated_ranks[0][slot][rank]) {
3090 train_ram_at_178(info, 0, slot,
3091 rank,
3092 totalrank,
3093 reg_178, 0,
3094 niter,
3095 timings);
3096 totalrank++;
3097 }
3098
3099 }
3100 } else {
3101 for (reg_178 = reg178_center - 12;
3102 reg_178 <= reg178_center + 12; reg_178 += 12) {
3103 totalrank = 0;
3104 set_178(reg_178);
3105 FOR_POPULATED_RANKS_BACKWARDS {
3106 train_ram_at_178(info, channel, slot, rank,
3107 totalrank, reg_178, 0, niter,
3108 timings);
3109 totalrank++;
3110 }
3111 }
3112 }
3113
3114 set_178(reg178_center);
3115 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3116 u16 tm0;
3117
3118 tm0 =
3119 choose_training(info, channel, slot, rank, lane, timings,
3120 reg178_center);
3121 write_500(info, channel, tm0,
3122 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3123 write_500(info, channel,
3124 tm0 +
3125 info->training.
3126 lane_timings[1][channel][slot][rank][lane] -
3127 info->training.
3128 lane_timings[0][channel][slot][rank][lane],
3129 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3130 }
3131
3132 totalrank = 0;
3133 FOR_POPULATED_RANKS_BACKWARDS {
3134 try_timing_offsets(info, channel, slot, rank, totalrank);
3135 totalrank++;
3136 }
Felix Held04be2dd2018-07-29 04:53:22 +02003137 MCHBAR8(0x243) = saved_243[0];
3138 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003139 write_1d0(0, 0x142, 3, 1);
3140 info->training.reg178_center = reg178_center;
3141}
3142
3143static void ram_training(struct raminfo *info)
3144{
3145 u16 saved_fc4;
3146
Felix Held04be2dd2018-07-29 04:53:22 +02003147 saved_fc4 = MCHBAR16(0xfc4);
3148 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003149
3150 if (info->revision >= 8)
3151 read_4090(info);
3152
3153 if (!try_cached_training(info))
3154 do_ram_training(info);
3155 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3156 && info->clock_speed_index < 2)
3157 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003158 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003159}
3160
Martin Roth468d02c2019-10-23 21:44:42 -06003161static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003162{
Martin Roth468d02c2019-10-23 21:44:42 -06003163 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003164 if (a > b) {
3165 t = a;
3166 a = b;
3167 b = t;
3168 }
3169 /* invariant a < b. */
3170 while (a) {
3171 t = b % a;
3172 b = a;
3173 a = t;
3174 }
3175 return b;
3176}
3177
3178static inline int div_roundup(int a, int b)
3179{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003180 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003181}
3182
Martin Roth468d02c2019-10-23 21:44:42 -06003183static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003184{
3185 return (a * b) / gcd(a, b);
3186}
3187
3188struct stru1 {
3189 u8 freqs_reversed;
3190 u8 freq_diff_reduced;
3191 u8 freq_min_reduced;
3192 u8 divisor_f4_to_fmax;
3193 u8 divisor_f3_to_fmax;
3194 u8 freq4_to_max_remainder;
3195 u8 freq3_to_2_remainder;
3196 u8 freq3_to_2_remaindera;
3197 u8 freq4_to_2_remainder;
3198 int divisor_f3_to_f1, divisor_f4_to_f2;
3199 int common_time_unit_ps;
3200 int freq_max_reduced;
3201};
3202
3203static void
3204compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3205 int num_cycles_2, int num_cycles_1, int round_it,
3206 int add_freqs, struct stru1 *result)
3207{
3208 int g;
3209 int common_time_unit_ps;
3210 int freq1_reduced, freq2_reduced;
3211 int freq_min_reduced;
3212 int freq_max_reduced;
3213 int freq3, freq4;
3214
3215 g = gcd(freq1, freq2);
3216 freq1_reduced = freq1 / g;
3217 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003218 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3219 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003220
3221 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3222 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3223 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3224 if (add_freqs) {
3225 freq3 += freq2_reduced;
3226 freq4 += freq1_reduced;
3227 }
3228
3229 if (round_it) {
3230 result->freq3_to_2_remainder = 0;
3231 result->freq3_to_2_remaindera = 0;
3232 result->freq4_to_max_remainder = 0;
3233 result->divisor_f4_to_f2 = 0;
3234 result->divisor_f3_to_f1 = 0;
3235 } else {
3236 if (freq2_reduced < freq1_reduced) {
3237 result->freq3_to_2_remainder =
3238 result->freq3_to_2_remaindera =
3239 freq3 % freq1_reduced - freq1_reduced + 1;
3240 result->freq4_to_max_remainder =
3241 -(freq4 % freq1_reduced);
3242 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3243 result->divisor_f4_to_f2 =
3244 (freq4 -
3245 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3246 result->freq4_to_2_remainder =
3247 -(char)((freq1_reduced - freq2_reduced) +
3248 ((u8) freq4 -
3249 (freq1_reduced -
3250 freq2_reduced)) % (u8) freq2_reduced);
3251 } else {
3252 if (freq2_reduced > freq1_reduced) {
3253 result->freq4_to_max_remainder =
3254 (freq4 % freq2_reduced) - freq2_reduced + 1;
3255 result->freq4_to_2_remainder =
3256 freq4 % freq_max_reduced -
3257 freq_max_reduced + 1;
3258 } else {
3259 result->freq4_to_max_remainder =
3260 -(freq4 % freq2_reduced);
3261 result->freq4_to_2_remainder =
3262 -(char)(freq4 % freq_max_reduced);
3263 }
3264 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3265 result->divisor_f3_to_f1 =
3266 (freq3 -
3267 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3268 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3269 result->freq3_to_2_remaindera =
3270 -(char)((freq_max_reduced - freq_min_reduced) +
3271 (freq3 -
3272 (freq_max_reduced -
3273 freq_min_reduced)) % freq1_reduced);
3274 }
3275 }
3276 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3277 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3278 if (round_it) {
3279 if (freq2_reduced > freq1_reduced) {
3280 if (freq3 % freq_max_reduced)
3281 result->divisor_f3_to_fmax++;
3282 }
3283 if (freq2_reduced < freq1_reduced) {
3284 if (freq4 % freq_max_reduced)
3285 result->divisor_f4_to_fmax++;
3286 }
3287 }
3288 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3289 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3290 result->freq_min_reduced = freq_min_reduced;
3291 result->common_time_unit_ps = common_time_unit_ps;
3292 result->freq_max_reduced = freq_max_reduced;
3293}
3294
3295static void
3296set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3297 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3298 int num_cycles_4, int reverse)
3299{
3300 struct stru1 vv;
3301 char multiplier;
3302
3303 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3304 0, 1, &vv);
3305
3306 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003307 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003308 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3309 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3310 div_roundup(num_cycles_1,
3311 vv.common_time_unit_ps) +
3312 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3313 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3314
3315 u32 y =
3316 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3317 vv.freq_max_reduced * multiplier)
3318 | (vv.
3319 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3320 multiplier) << 16) | ((u8) (vv.
3321 freq_min_reduced
3322 *
3323 multiplier)
3324 << 24);
3325 u32 x =
3326 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3327 divisor_f3_to_f1
3328 << 16)
3329 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3330 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003331 MCHBAR32(reg) = y;
3332 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003333 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003334 MCHBAR32(reg + 4) = y;
3335 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003336 }
3337}
3338
3339static void
3340set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3341 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3342 int num_cycles_4)
3343{
3344 struct stru1 ratios1;
3345 struct stru1 ratios2;
3346
3347 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3348 0, 1, &ratios2);
3349 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3350 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003351 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003352 ratios1.freq4_to_max_remainder | (ratios2.
3353 freq4_to_max_remainder
3354 << 8)
3355 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3356 divisor_f4_to_fmax
3357 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003358 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3359 (ratios2.freq4_to_max_remainder << 8) |
3360 (ratios1.divisor_f4_to_fmax << 16) |
3361 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003362}
3363
3364static void
3365set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3366 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3367{
3368 struct stru1 ratios;
3369
3370 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3371 round_it, add_freqs, &ratios);
3372 switch (mode) {
3373 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003374 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3375 (ratios.freqs_reversed << 8);
3376 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3377 (ratios.freq4_to_max_remainder << 8) |
3378 (ratios.divisor_f3_to_fmax << 16) |
3379 (ratios.divisor_f4_to_fmax << 20) |
3380 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003381 break;
3382
3383 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003384 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3385 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003386 break;
3387
3388 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003389 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3390 (ratios.freq4_to_max_remainder << 8) |
3391 (ratios.divisor_f3_to_fmax << 16) |
3392 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003393 break;
3394
3395 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003396 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3397 (ratios.divisor_f4_to_fmax << 8) |
3398 (ratios.freqs_reversed << 12) |
3399 (ratios.freq_min_reduced << 16) |
3400 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003401 break;
3402 }
3403}
3404
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003405static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406{
3407 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3408 0, 1);
3409 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3410 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3411 1);
3412 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3413 frequency_11(info), 1231, 1524, 0, 1);
3414 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3415 frequency_11(info) / 2, 1278, 2008, 0, 1);
3416 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3417 1167, 1539, 0, 1);
3418 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3419 frequency_11(info) / 2, 1403, 1318, 0, 1);
3420 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3421 1);
3422 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3423 1);
3424 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3425 1, 1);
3426 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3427 1);
3428 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3429 frequency_11(info) / 2, 4000, 0, 0, 0);
3430 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3431 frequency_11(info) / 2, 4000, 4000, 0, 0);
3432
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003433 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003434 printk(RAM_SPEW, "[6dc] <= %x\n",
3435 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003436 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003437 } else
3438 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3439 info->delay46_ps[0], 0,
3440 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003441 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3442 frequency_11(info), 2500, 0, 0, 0);
3443 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3444 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003445 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003446 printk(RAM_SPEW, "[6e8] <= %x\n",
3447 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003448 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003449 } else
3450 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3451 info->delay46_ps[1], 0,
3452 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003453 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3454 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3455 470, 0);
3456 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3457 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3458 454, 459, 0);
3459 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3460 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3461 2588, 0);
3462 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3463 2405, 0);
3464 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3465 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3466 480, 0);
3467 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003468 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3469 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003470}
3471
3472static u16 get_max_timing(struct raminfo *info, int channel)
3473{
3474 int slot, rank, lane;
3475 u16 ret = 0;
3476
Felix Held04be2dd2018-07-29 04:53:22 +02003477 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003478 return 384;
3479
3480 if (info->revision < 8)
3481 return 256;
3482
3483 for (slot = 0; slot < NUM_SLOTS; slot++)
3484 for (rank = 0; rank < NUM_RANKS; rank++)
3485 if (info->populated_ranks[channel][slot][rank])
3486 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003487 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488 get_timing_register_addr
3489 (lane, 0, slot,
3490 rank), 9));
3491 return ret;
3492}
3493
3494static void set_274265(struct raminfo *info)
3495{
3496 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3497 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3498 int delay_e_over_cycle_ps;
3499 int cycletime_ps;
3500 int channel;
3501
3502 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003503 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3505 cycletime_ps =
3506 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3507 delay_d_ps =
3508 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3509 - info->some_delay_3_ps_rounded + 200;
3510 if (!
3511 ((info->silicon_revision == 0
3512 || info->silicon_revision == 1)
3513 && (info->revision >= 8)))
3514 delay_d_ps += halfcycle_ps(info) * 2;
3515 delay_d_ps +=
3516 halfcycle_ps(info) * (!info->revision_flag_1 +
3517 info->some_delay_2_halfcycles_ceil +
3518 2 * info->some_delay_1_cycle_floor +
3519 info->clock_speed_index +
3520 2 * info->cas_latency - 7 + 11);
3521 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3522
Felix Held04be2dd2018-07-29 04:53:22 +02003523 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3524 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3525 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003526 delay_d_ps += 650;
3527 delay_c_ps = delay_d_ps + 1800;
3528 if (delay_c_ps <= delay_a_ps)
3529 delay_e_ps = 0;
3530 else
3531 delay_e_ps =
3532 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3533 cycletime_ps);
3534
3535 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3536 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3537 delay_f_cycles =
3538 div_roundup(2500 - delay_e_over_cycle_ps,
3539 2 * halfcycle_ps(info));
3540 if (delay_f_cycles > delay_e_cycles) {
3541 info->delay46_ps[channel] = delay_e_ps;
3542 delay_e_cycles = 0;
3543 } else {
3544 info->delay46_ps[channel] =
3545 delay_e_over_cycle_ps +
3546 2 * halfcycle_ps(info) * delay_f_cycles;
3547 delay_e_cycles -= delay_f_cycles;
3548 }
3549
3550 if (info->delay46_ps[channel] < 2500) {
3551 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003552 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003553 }
3554 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3555 if (delay_b_ps <= delay_a_ps)
3556 delay_b_ps = 0;
3557 else
3558 delay_b_ps -= delay_a_ps;
3559 info->delay54_ps[channel] =
3560 cycletime_ps * div_roundup(delay_b_ps,
3561 cycletime_ps) -
3562 2 * halfcycle_ps(info) * delay_e_cycles;
3563 if (info->delay54_ps[channel] < 2500)
3564 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003565 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003566 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3567 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003568 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003569 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003570 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003571 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3572 4 * halfcycle_ps(info)) - 6;
3573 MCHBAR32((channel << 10) + 0x274) =
3574 info->training.reg274265[channel][1] |
3575 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003576 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003577 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3578 4 * halfcycle_ps(info)) + 1;
3579 MCHBAR16((channel << 10) + 0x265) =
3580 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003581 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003582 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003583 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003584 else
Felix Held04be2dd2018-07-29 04:53:22 +02003585 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003586}
3587
3588static void restore_274265(struct raminfo *info)
3589{
3590 int channel;
3591
3592 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003593 MCHBAR32((channel << 10) + 0x274) =
3594 (info->cached_training->reg274265[channel][0] << 16) |
3595 info->cached_training->reg274265[channel][1];
3596 MCHBAR16((channel << 10) + 0x265) =
3597 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003599 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003600 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003601 else
Felix Held04be2dd2018-07-29 04:53:22 +02003602 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603}
3604
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605static void dmi_setup(void)
3606{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003607 gav(DMIBAR8(0x254));
3608 DMIBAR8(0x254) = 0x1;
3609 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003610 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611
Angel Ponsd071c4d2020-09-14 23:51:35 +02003612 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613
3614 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3615 DEFAULT_GPIOBASE | 0x38);
3616 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3617}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003619void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003622 u16 ggc;
3623 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624
Felix Held04be2dd2018-07-29 04:53:22 +02003625 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3627 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003628 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003629 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631
3632 dmi_setup();
3633
Felix Held04be2dd2018-07-29 04:53:22 +02003634 MCHBAR16(0x1170) = 0xa880;
3635 MCHBAR8(0x11c1) = 0x1;
3636 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003637 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003639 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3640 /* 0 for 32MB */
3641 gfxsize = 0;
3642 }
3643
3644 ggc = 0xb00 | ((gfxsize + 5) << 4);
3645
Angel Pons16fe1e02020-07-22 16:12:33 +02003646 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647
3648 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003649 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650
3651 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003652 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003653 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003654 MCHBAR16_OR(0x2c30, 0x200);
3655 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003656 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003657 pci_read_config8(GMA, MSAC); // = 0x2
3658 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003659 RCBA8(0x2318);
3660 RCBA8(0x2318) = 0x47;
3661 RCBA8(0x2320);
3662 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663 }
3664
Felix Heldf83d80b2018-07-29 05:30:30 +02003665 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666
Angel Pons16fe1e02020-07-22 16:12:33 +02003667 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003668 gav(RCBA32(0x3428));
3669 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003670}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003672void raminit(const int s3resume, const u8 *spd_addrmap)
3673{
Martin Roth468d02c2019-10-23 21:44:42 -06003674 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003675 int i;
3676 struct raminfo info;
3677 u8 x2ca8;
3678 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003679 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003680
Felix Held04be2dd2018-07-29 04:53:22 +02003681 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003682
3683 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3684
Angel Pons16fe1e02020-07-22 16:12:33 +02003685 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686
3687 memset(&info, 0x5a, sizeof(info));
3688
3689 info.last_500_command[0] = 0;
3690 info.last_500_command[1] = 0;
3691
3692 info.fsb_frequency = 135 * 2;
3693 info.board_lane_delay[0] = 0x14;
3694 info.board_lane_delay[1] = 0x07;
3695 info.board_lane_delay[2] = 0x07;
3696 info.board_lane_delay[3] = 0x08;
3697 info.board_lane_delay[4] = 0x56;
3698 info.board_lane_delay[5] = 0x04;
3699 info.board_lane_delay[6] = 0x04;
3700 info.board_lane_delay[7] = 0x05;
3701 info.board_lane_delay[8] = 0x10;
3702
3703 info.training.reg_178 = 0;
3704 info.training.reg_10b = 0;
3705
Angel Ponsa3868292021-01-15 22:10:13 +01003706 /* Wait for some bit, maybe TXT clear. */
3707 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3708 ;
3709
3710 /* Wait for ME to be ready */
3711 intel_early_me_init();
3712 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713
3714 /* before SPD */
3715 timestamp_add_now(101);
3716
Felix Held29a9c072018-07-29 01:34:45 +02003717 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3719
3720 info.use_ecc = 1;
3721 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003722 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723 int v;
3724 int try;
3725 int addr;
3726 const u8 useful_addresses[] = {
3727 DEVICE_TYPE,
3728 MODULE_TYPE,
3729 DENSITY,
3730 RANKS_AND_DQ,
3731 MEMORY_BUS_WIDTH,
3732 TIMEBASE_DIVIDEND,
3733 TIMEBASE_DIVISOR,
3734 CYCLETIME,
3735 CAS_LATENCIES_LSB,
3736 CAS_LATENCIES_MSB,
3737 CAS_LATENCY_TIME,
3738 0x11, 0x12, 0x13, 0x14, 0x15,
3739 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3740 0x1c, 0x1d,
3741 THERMAL_AND_REFRESH,
3742 0x20,
3743 REFERENCE_RAW_CARD_USED,
3744 RANK1_ADDRESS_MAPPING,
3745 0x75, 0x76, 0x77, 0x78,
3746 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3747 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3748 0x85, 0x86, 0x87, 0x88,
3749 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3750 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3751 0x95
3752 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003753 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003754 continue;
3755 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003756 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003757 DEVICE_TYPE);
3758 if (v >= 0)
3759 break;
3760 }
3761 if (v < 0)
3762 continue;
3763 for (addr = 0;
3764 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003765 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766 gav(info.
3767 spd[channel][0][useful_addresses
3768 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003769 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003770 useful_addresses
3771 [addr]));
3772 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3773 die("Only DDR3 is supported");
3774
3775 v = info.spd[channel][0][RANKS_AND_DQ];
3776 info.populated_ranks[channel][0][0] = 1;
3777 info.populated_ranks[channel][0][1] =
3778 ((v >> 3) & 7);
3779 if (((v >> 3) & 7) > 1)
3780 die("At most 2 ranks are supported");
3781 if ((v & 7) == 0 || (v & 7) > 2)
3782 die("Only x8 and x16 modules are supported");
3783 if ((info.
3784 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3785 && (info.
3786 spd[channel][slot][MODULE_TYPE] & 0xF)
3787 != 3)
3788 die("Registered memory is not supported");
3789 info.is_x16_module[channel][0] = (v & 7) - 1;
3790 info.density[channel][slot] =
3791 info.spd[channel][slot][DENSITY] & 0xF;
3792 if (!
3793 (info.
3794 spd[channel][slot][MEMORY_BUS_WIDTH] &
3795 0x18))
3796 info.use_ecc = 0;
3797 }
3798
3799 gav(0x55);
3800
3801 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3802 int v = 0;
3803 for (slot = 0; slot < NUM_SLOTS; slot++)
3804 for (rank = 0; rank < NUM_RANKS; rank++)
3805 v |= info.
3806 populated_ranks[channel][slot][rank]
3807 << (2 * slot + rank);
3808 info.populated_ranks_mask[channel] = v;
3809 }
3810
3811 gav(0x55);
3812
Angel Pons16fe1e02020-07-22 16:12:33 +02003813 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003814 }
3815
3816 /* after SPD */
3817 timestamp_add_now(102);
3818
Felix Held04be2dd2018-07-29 04:53:22 +02003819 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820
3821 collect_system_info(&info);
3822 calculate_timings(&info);
3823
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003824 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003825 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003826 if (x2ca8 == 0 && (reg8 & 0x80)) {
3827 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3828 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3829 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3830 */
3831
3832 /* Clear bit7. */
3833
3834 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3835 (reg8 & ~(1 << 7)));
3836
3837 printk(BIOS_INFO,
3838 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003839 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840 }
3841 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003842
3843 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003844 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3845 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003846
3847 compute_derived_timings(&info);
3848
3849 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003850 gav(MCHBAR8(0x164));
3851 MCHBAR8(0x164) = 0x26;
3852 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003853 }
3854
Felix Held04be2dd2018-07-29 04:53:22 +02003855 MCHBAR32_OR(0x18b4, 0x210000);
3856 MCHBAR32_OR(0x1890, 0x2000000);
3857 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003858
Angel Ponsa457e352020-07-22 18:17:33 +02003859 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3860 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861
Felix Held04be2dd2018-07-29 04:53:22 +02003862 gav(MCHBAR16(0x2c10));
3863 MCHBAR16(0x2c10) = 0x412;
3864 gav(MCHBAR16(0x2c10));
3865 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866
Felix Held04be2dd2018-07-29 04:53:22 +02003867 gav(MCHBAR8(0x2ca8)); // !!!!
3868 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869
Angel Ponsa457e352020-07-22 18:17:33 +02003870 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3871 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003872 gav(MCHBAR32(0x1c04)); // !!!!
3873 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874
3875 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003876 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003877 }
3878
Felix Held04be2dd2018-07-29 04:53:22 +02003879 MCHBAR32(0x18d8) = 0x120000;
3880 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003881 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3882 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003883 MCHBAR32(0x18d8) = 0x40000;
3884 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003885 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3886 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003887 MCHBAR32(0x18d8) = 0x180000;
3888 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003889 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3890 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003891 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
Felix Held04be2dd2018-07-29 04:53:22 +02003893 gav(MCHBAR32(0x18dc)); // !!!!
3894 MCHBAR32(0x18dc) = 0x3;
3895 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003896
3897 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003898 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003899 }
3900
Felix Held04be2dd2018-07-29 04:53:22 +02003901 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003902 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003903 MCHBAR32(0x1a10) = 0x4200010e;
3904 MCHBAR32_OR(0x18b8, 0x200);
3905 gav(MCHBAR32(0x1918)); // !!!!
3906 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003907
Felix Held04be2dd2018-07-29 04:53:22 +02003908 gav(MCHBAR32(0x18b8)); // !!!!
3909 MCHBAR32(0x18b8) = 0xe00;
3910 gav(MCHBAR32(0x182c)); // !!!!
3911 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003912 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3913 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3915 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
Felix Held04be2dd2018-07-29 04:53:22 +02003917 MCHBAR32_AND(0x18b4, 0xffff7fff);
3918 gav(MCHBAR32(0x1a68)); // !!!!
3919 MCHBAR32(0x1a68) = 0x343800;
3920 gav(MCHBAR32(0x1e68)); // !!!!
3921 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922
3923 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925 }
3926
Angel Pons08143572020-07-22 17:47:06 +02003927 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3928 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3929 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3930 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3931 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003932 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3933 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003934 gav(MCHBAR32(0x1af0)); // !!!!
3935 gav(MCHBAR32(0x1af0)); // !!!!
3936 MCHBAR32(0x1af0) = 0x1f020003;
3937 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003938
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003939 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003940 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003941 }
3942
Felix Held04be2dd2018-07-29 04:53:22 +02003943 gav(MCHBAR32(0x1890)); // !!!!
3944 MCHBAR32(0x1890) = 0x80102;
3945 gav(MCHBAR32(0x18b4)); // !!!!
3946 MCHBAR32(0x18b4) = 0x216000;
3947 MCHBAR32(0x18a4) = 0x22222222;
3948 MCHBAR32(0x18a8) = 0x22222222;
3949 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950
3951 udelay(1000);
3952
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003953 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003955 if (x2ca8 == 0) {
3956 int j;
3957 if (s3resume && info.cached_training) {
3958 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003959 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003960 info.cached_training->reg2ca9_bit0);
3961 for (i = 0; i < 2; i++)
3962 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003963 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003964 i, j, info.cached_training->reg274265[i][j]);
3965 } else {
3966 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003967 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003968 info.training.reg2ca9_bit0);
3969 for (i = 0; i < 2; i++)
3970 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003971 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003972 i, j, info.training.reg274265[i][j]);
3973 }
3974
3975 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976
3977 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003978 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003979 }
3980
3981 udelay(1000);
3982
3983 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003984 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003985 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003986 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3987 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3988 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003989
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003990 MCHBAR8(0x1150);
3991 MCHBAR8(0x1151);
3992 MCHBAR8(0x1022);
3993 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02003994 MCHBAR32(0x1300) = 0x60606060;
3995 MCHBAR32(0x1304) = 0x60606060;
3996 MCHBAR32(0x1308) = 0x78797a7b;
3997 MCHBAR32(0x130c) = 0x7c7d7e7f;
3998 MCHBAR32(0x1310) = 0x60606060;
3999 MCHBAR32(0x1314) = 0x60606060;
4000 MCHBAR32(0x1318) = 0x60606060;
4001 MCHBAR32(0x131c) = 0x60606060;
4002 MCHBAR32(0x1320) = 0x50515253;
4003 MCHBAR32(0x1324) = 0x54555657;
4004 MCHBAR32(0x1328) = 0x58595a5b;
4005 MCHBAR32(0x132c) = 0x5c5d5e5f;
4006 MCHBAR32(0x1330) = 0x40414243;
4007 MCHBAR32(0x1334) = 0x44454647;
4008 MCHBAR32(0x1338) = 0x48494a4b;
4009 MCHBAR32(0x133c) = 0x4c4d4e4f;
4010 MCHBAR32(0x1340) = 0x30313233;
4011 MCHBAR32(0x1344) = 0x34353637;
4012 MCHBAR32(0x1348) = 0x38393a3b;
4013 MCHBAR32(0x134c) = 0x3c3d3e3f;
4014 MCHBAR32(0x1350) = 0x20212223;
4015 MCHBAR32(0x1354) = 0x24252627;
4016 MCHBAR32(0x1358) = 0x28292a2b;
4017 MCHBAR32(0x135c) = 0x2c2d2e2f;
4018 MCHBAR32(0x1360) = 0x10111213;
4019 MCHBAR32(0x1364) = 0x14151617;
4020 MCHBAR32(0x1368) = 0x18191a1b;
4021 MCHBAR32(0x136c) = 0x1c1d1e1f;
4022 MCHBAR32(0x1370) = 0x10203;
4023 MCHBAR32(0x1374) = 0x4050607;
4024 MCHBAR32(0x1378) = 0x8090a0b;
4025 MCHBAR32(0x137c) = 0xc0d0e0f;
4026 MCHBAR8(0x11cc) = 0x4e;
4027 MCHBAR32(0x1110) = 0x73970404;
4028 MCHBAR32(0x1114) = 0x72960404;
4029 MCHBAR32(0x1118) = 0x6f950404;
4030 MCHBAR32(0x111c) = 0x6d940404;
4031 MCHBAR32(0x1120) = 0x6a930404;
4032 MCHBAR32(0x1124) = 0x68a41404;
4033 MCHBAR32(0x1128) = 0x66a21404;
4034 MCHBAR32(0x112c) = 0x63a01404;
4035 MCHBAR32(0x1130) = 0x609e1404;
4036 MCHBAR32(0x1134) = 0x5f9c1404;
4037 MCHBAR32(0x1138) = 0x5c961404;
4038 MCHBAR32(0x113c) = 0x58a02404;
4039 MCHBAR32(0x1140) = 0x54942404;
4040 MCHBAR32(0x1190) = 0x900080a;
4041 MCHBAR16(0x11c0) = 0xc40b;
4042 MCHBAR16(0x11c2) = 0x303;
4043 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004044 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004045 MCHBAR32(0x11b8) = 0x70c3000;
4046 MCHBAR8(0x11ec) = 0xa;
4047 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004048 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004049 MCHBAR16(0x11ca) = 0xfa;
4050 MCHBAR32(0x11e4) = 0x4e20;
4051 MCHBAR8(0x11bc) = 0xf;
4052 MCHBAR16(0x11da) = 0x19;
4053 MCHBAR16(0x11ba) = 0x470c;
4054 MCHBAR32(0x1680) = 0xe6ffe4ff;
4055 MCHBAR32(0x1684) = 0xdeffdaff;
4056 MCHBAR32(0x1688) = 0xd4ffd0ff;
4057 MCHBAR32(0x168c) = 0xccffc6ff;
4058 MCHBAR32(0x1690) = 0xc0ffbeff;
4059 MCHBAR32(0x1694) = 0xb8ffb0ff;
4060 MCHBAR32(0x1698) = 0xa8ff0000;
4061 MCHBAR32(0x169c) = 0xc00;
4062 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004063 }
4064
Felix Held04be2dd2018-07-29 04:53:22 +02004065 MCHBAR32(0x124c) = 0x15040d00;
4066 MCHBAR32(0x1250) = 0x7f0000;
4067 MCHBAR32(0x1254) = 0x1e220004;
4068 MCHBAR32(0x1258) = 0x4000004;
4069 MCHBAR32(0x1278) = 0x0;
4070 MCHBAR32(0x125c) = 0x0;
4071 MCHBAR32(0x1260) = 0x0;
4072 MCHBAR32(0x1264) = 0x0;
4073 MCHBAR32(0x1268) = 0x0;
4074 MCHBAR32(0x126c) = 0x0;
4075 MCHBAR32(0x1270) = 0x0;
4076 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004077 }
4078
4079 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004080 MCHBAR16(0x1214) = 0x320;
4081 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004082 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4083 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004084 MCHBAR32(0x1400) = 0x13040020;
4085 MCHBAR32(0x1404) = 0xe090120;
4086 MCHBAR32(0x1408) = 0x5120220;
4087 MCHBAR32(0x140c) = 0x5120330;
4088 MCHBAR32(0x1410) = 0xe090220;
4089 MCHBAR32(0x1414) = 0x1010001;
4090 MCHBAR32(0x1418) = 0x1110000;
4091 MCHBAR32(0x141c) = 0x9020020;
4092 MCHBAR32(0x1420) = 0xd090220;
4093 MCHBAR32(0x1424) = 0x2090220;
4094 MCHBAR32(0x1428) = 0x2090330;
4095 MCHBAR32(0x142c) = 0xd090220;
4096 MCHBAR32(0x1430) = 0x1010001;
4097 MCHBAR32(0x1434) = 0x1110000;
4098 MCHBAR32(0x1438) = 0x11040020;
4099 MCHBAR32(0x143c) = 0x4030220;
4100 MCHBAR32(0x1440) = 0x1060220;
4101 MCHBAR32(0x1444) = 0x1060330;
4102 MCHBAR32(0x1448) = 0x4030220;
4103 MCHBAR32(0x144c) = 0x1010001;
4104 MCHBAR32(0x1450) = 0x1110000;
4105 MCHBAR32(0x1454) = 0x4010020;
4106 MCHBAR32(0x1458) = 0xb090220;
4107 MCHBAR32(0x145c) = 0x1090220;
4108 MCHBAR32(0x1460) = 0x1090330;
4109 MCHBAR32(0x1464) = 0xb090220;
4110 MCHBAR32(0x1468) = 0x1010001;
4111 MCHBAR32(0x146c) = 0x1110000;
4112 MCHBAR32(0x1470) = 0xf040020;
4113 MCHBAR32(0x1474) = 0xa090220;
4114 MCHBAR32(0x1478) = 0x1120220;
4115 MCHBAR32(0x147c) = 0x1120330;
4116 MCHBAR32(0x1480) = 0xa090220;
4117 MCHBAR32(0x1484) = 0x1010001;
4118 MCHBAR32(0x1488) = 0x1110000;
4119 MCHBAR32(0x148c) = 0x7020020;
4120 MCHBAR32(0x1490) = 0x1010220;
4121 MCHBAR32(0x1494) = 0x10210;
4122 MCHBAR32(0x1498) = 0x10320;
4123 MCHBAR32(0x149c) = 0x1010220;
4124 MCHBAR32(0x14a0) = 0x1010001;
4125 MCHBAR32(0x14a4) = 0x1110000;
4126 MCHBAR32(0x14a8) = 0xd040020;
4127 MCHBAR32(0x14ac) = 0x8090220;
4128 MCHBAR32(0x14b0) = 0x1111310;
4129 MCHBAR32(0x14b4) = 0x1111420;
4130 MCHBAR32(0x14b8) = 0x8090220;
4131 MCHBAR32(0x14bc) = 0x1010001;
4132 MCHBAR32(0x14c0) = 0x1110000;
4133 MCHBAR32(0x14c4) = 0x3010020;
4134 MCHBAR32(0x14c8) = 0x7090220;
4135 MCHBAR32(0x14cc) = 0x1081310;
4136 MCHBAR32(0x14d0) = 0x1081420;
4137 MCHBAR32(0x14d4) = 0x7090220;
4138 MCHBAR32(0x14d8) = 0x1010001;
4139 MCHBAR32(0x14dc) = 0x1110000;
4140 MCHBAR32(0x14e0) = 0xb040020;
4141 MCHBAR32(0x14e4) = 0x2030220;
4142 MCHBAR32(0x14e8) = 0x1051310;
4143 MCHBAR32(0x14ec) = 0x1051420;
4144 MCHBAR32(0x14f0) = 0x2030220;
4145 MCHBAR32(0x14f4) = 0x1010001;
4146 MCHBAR32(0x14f8) = 0x1110000;
4147 MCHBAR32(0x14fc) = 0x5020020;
4148 MCHBAR32(0x1500) = 0x5090220;
4149 MCHBAR32(0x1504) = 0x2071310;
4150 MCHBAR32(0x1508) = 0x2071420;
4151 MCHBAR32(0x150c) = 0x5090220;
4152 MCHBAR32(0x1510) = 0x1010001;
4153 MCHBAR32(0x1514) = 0x1110000;
4154 MCHBAR32(0x1518) = 0x7040120;
4155 MCHBAR32(0x151c) = 0x2090220;
4156 MCHBAR32(0x1520) = 0x70b1210;
4157 MCHBAR32(0x1524) = 0x70b1310;
4158 MCHBAR32(0x1528) = 0x2090220;
4159 MCHBAR32(0x152c) = 0x1010001;
4160 MCHBAR32(0x1530) = 0x1110000;
4161 MCHBAR32(0x1534) = 0x1010110;
4162 MCHBAR32(0x1538) = 0x1081310;
4163 MCHBAR32(0x153c) = 0x5041200;
4164 MCHBAR32(0x1540) = 0x5041310;
4165 MCHBAR32(0x1544) = 0x1081310;
4166 MCHBAR32(0x1548) = 0x1010001;
4167 MCHBAR32(0x154c) = 0x1110000;
4168 MCHBAR32(0x1550) = 0x1040120;
4169 MCHBAR32(0x1554) = 0x4051210;
4170 MCHBAR32(0x1558) = 0xd051200;
4171 MCHBAR32(0x155c) = 0xd051200;
4172 MCHBAR32(0x1560) = 0x4051210;
4173 MCHBAR32(0x1564) = 0x1010001;
4174 MCHBAR32(0x1568) = 0x1110000;
4175 MCHBAR16(0x1222) = 0x220a;
4176 MCHBAR16(0x123c) = 0x1fc0;
4177 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004178 }
4179
Felix Heldf83d80b2018-07-29 05:30:30 +02004180 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004181 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004182 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004183
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004184 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004185
4186 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004187 MCHBAR8_AND(0x2ca8, ~3);
4188 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004189 /* This issues a CPU reset without resetting the platform */
4190 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004191 /* Write back the S3 state to PM1_CNT to let the reset CPU
4192 know it also needs to take the s3 path. */
4193 if (s3resume)
4194 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4195 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004196 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004197 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004198 }
4199
Felix Held04be2dd2018-07-29 04:53:22 +02004200 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004201 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004202 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004203 MCHBAR16(0x2c20); // !!!!
4204 MCHBAR16(0x2c10); // !!!!
4205 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004206 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004207 udelay(1000);
4208 write_1d0(0, 0x33d, 0, 0);
4209 write_500(&info, 0, 0, 0xb61, 0, 0);
4210 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004211 MCHBAR32(0x1a30) = 0x0;
4212 MCHBAR32(0x1a34) = 0x0;
4213 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4214 (info.populated_ranks[0][0][0] * 0xa0);
4215 MCHBAR16(0x616) = 0x26a;
4216 MCHBAR32(0x134) = 0x856000;
4217 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004218 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4219 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004220 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004221 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4222 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004223 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004224 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004225 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4226 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004227 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4228 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4229 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4230 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4231 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4232 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4233 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4234 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4235 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4236 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004237 }
4238
4239 write_1d0(0x4, 0x151, 4, 1);
4240 write_1d0(0, 0x142, 3, 1);
4241 rdmsr(0x1ac); // !!!!
4242 write_500(&info, 1, 1, 0x6b3, 4, 1);
4243 write_500(&info, 1, 1, 0x6cf, 4, 1);
4244
Angel Pons244f4552021-01-15 20:41:36 +01004245 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004246
4247 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4248 populated_ranks[0]
4249 [0][0]) << 0),
4250 0x1d1, 3, 1);
4251 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004252 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4253 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254 }
4255
4256 set_334(0);
4257
4258 program_base_timings(&info);
4259
Felix Held04be2dd2018-07-29 04:53:22 +02004260 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004261
4262 write_1d0(0x2, 0x1d5, 2, 1);
4263 write_1d0(0x20, 0x166, 7, 1);
4264 write_1d0(0x0, 0xeb, 3, 1);
4265 write_1d0(0x0, 0xf3, 6, 1);
4266
4267 for (channel = 0; channel < NUM_CHANNELS; channel++)
4268 for (lane = 0; lane < 9; lane++) {
4269 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4270 u8 a;
4271 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4272 write_500(&info, channel, a, addr, 6, 1);
4273 }
4274
4275 udelay(1000);
4276
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004277 if (s3resume) {
4278 if (info.cached_training == NULL) {
4279 u32 reg32;
4280 printk(BIOS_ERR,
4281 "Couldn't find training data. Rebooting\n");
4282 reg32 = inl(DEFAULT_PMBASE + 0x04);
4283 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004284 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004285 }
4286 int tm;
4287 info.training = *info.cached_training;
4288 for (tm = 0; tm < 4; tm++)
4289 for (channel = 0; channel < NUM_CHANNELS; channel++)
4290 for (slot = 0; slot < NUM_SLOTS; slot++)
4291 for (rank = 0; rank < NUM_RANKS; rank++)
4292 for (lane = 0; lane < 9; lane++)
4293 write_500(&info,
4294 channel,
4295 info.training.
4296 lane_timings
4297 [tm][channel]
4298 [slot][rank]
4299 [lane],
4300 get_timing_register_addr
4301 (lane, tm,
4302 slot, rank),
4303 9, 0);
4304 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4305 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4306 }
4307
Felix Heldf83d80b2018-07-29 05:30:30 +02004308 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004309 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004310 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004311 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004312
4313 program_board_delay(&info);
4314
Felix Held04be2dd2018-07-29 04:53:22 +02004315 MCHBAR8(0x5ff) = 0x0;
4316 MCHBAR8(0x5ff) = 0x80;
4317 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004318
Felix Held04be2dd2018-07-29 04:53:22 +02004319 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004320 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004321 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004322 gav(read_1d0(0x14b, 7)); // = 0x81023100
4323 write_1d0(0x30, 0x14b, 7, 1);
4324 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4325 write_1d0(7, 0xd6, 6, 1);
4326 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4327 write_1d0(7, 0x328, 6, 1);
4328
4329 for (channel = 0; channel < NUM_CHANNELS; channel++)
4330 set_4cf(&info, channel,
4331 info.populated_ranks[channel][0][0] ? 8 : 0);
4332
4333 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4334 write_1d0(2, 0x116, 4, 1);
4335 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4336 write_1d0(0, 0xae, 6, 1);
4337 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4338 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004339 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4340 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004341 MCHBAR32_AND(0x140, ~0x07000000);
4342 MCHBAR32_AND(0x138, ~0x07000000);
4343 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004344 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004345 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004346 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004347
4348 {
4349 u32 t;
4350 u8 val_a1;
4351 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4352 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4353 rmw_1d0(0x320, 0x07,
Angel Pons244f4552021-01-15 20:41:36 +01004354 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004355 rmw_1d0(0x14b, 0x78,
4356 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004357 4), 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004358 rmw_1d0(0xce, 0x38,
4359 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004360 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004361 }
4362
4363 for (channel = 0; channel < NUM_CHANNELS; channel++)
4364 set_4cf(&info, channel,
4365 info.populated_ranks[channel][0][0] ? 9 : 1);
4366
Angel Pons244f4552021-01-15 20:41:36 +01004367 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004368 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004369 write_1d0(2, 0xae, 6, 1);
4370 write_1d0(2, 0x300, 6, 1);
4371 write_1d0(2, 0x121, 3, 1);
4372 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4373 write_1d0(4, 0xd6, 6, 1);
4374 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4375 write_1d0(4, 0x328, 6, 1);
4376
4377 for (channel = 0; channel < NUM_CHANNELS; channel++)
4378 set_4cf(&info, channel,
4379 info.populated_ranks[channel][0][0] ? 9 : 0);
4380
Felix Held04be2dd2018-07-29 04:53:22 +02004381 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4382 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004383 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004384 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004385 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4386 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4387 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4388 write_1d0(0, 0x21c, 6, 1);
4389 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4390 write_1d0(0x35, 0x14b, 7, 1);
4391
4392 for (channel = 0; channel < NUM_CHANNELS; channel++)
4393 set_4cf(&info, channel,
4394 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4395
4396 set_334(1);
4397
Felix Held04be2dd2018-07-29 04:53:22 +02004398 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004399
4400 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4401 write_500(&info, channel,
4402 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4403 1);
4404 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4405 }
Felix Held04be2dd2018-07-29 04:53:22 +02004406 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4407 MCHBAR16(0x6c0) = 0x14a0;
4408 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4409 MCHBAR16(0x232) = 0x8;
4410 /* 0x40004 or 0 depending on ? */
4411 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4412 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4413 MCHBAR32(0x128) = 0x2150d05;
4414 MCHBAR8(0x12c) = 0x1f;
4415 MCHBAR8(0x12d) = 0x56;
4416 MCHBAR8(0x12e) = 0x31;
4417 MCHBAR8(0x12f) = 0x0;
4418 MCHBAR8(0x271) = 0x2;
4419 MCHBAR8(0x671) = 0x2;
4420 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004421 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004422 MCHBAR32(0x294 + (channel << 10)) =
4423 (info.populated_ranks_mask[channel] & 3) << 16;
4424 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4425 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004426 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004427 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4428 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004429
4430 if (!s3resume)
4431 jedec_init(&info);
4432
4433 int totalrank = 0;
4434 for (channel = 0; channel < NUM_CHANNELS; channel++)
4435 for (slot = 0; slot < NUM_SLOTS; slot++)
4436 for (rank = 0; rank < NUM_RANKS; rank++)
4437 if (info.populated_ranks[channel][slot][rank]) {
4438 jedec_read(&info, channel, slot, rank,
4439 totalrank, 0xa, 0x400);
4440 totalrank++;
4441 }
4442
Felix Held04be2dd2018-07-29 04:53:22 +02004443 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004444
Felix Heldf83d80b2018-07-29 05:30:30 +02004445 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4446 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004447
4448 if (!s3resume) {
4449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004450 MCHBAR32(0x294 + (channel << 10)) =
4451 (info.populated_ranks_mask[channel] & 3) << 16;
4452 MCHBAR16(0x298 + (channel << 10)) =
4453 info.populated_ranks[channel][0][0] |
4454 (info.populated_ranks[channel][0][1] << 5);
4455 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004456 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004457 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004458
4459 {
4460 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004461 a = MCHBAR8(0x243);
4462 b = MCHBAR8(0x643);
4463 MCHBAR8(0x243) = a | 2;
4464 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004465 }
4466
4467 write_1d0(7, 0x19b, 3, 1);
4468 write_1d0(7, 0x1c0, 3, 1);
4469 write_1d0(4, 0x1c6, 4, 1);
4470 write_1d0(4, 0x1cc, 4, 1);
4471 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4472 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004473 MCHBAR32(0x584) = 0xfffff;
4474 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475
4476 for (channel = 0; channel < NUM_CHANNELS; channel++)
4477 for (slot = 0; slot < NUM_SLOTS; slot++)
4478 for (rank = 0; rank < NUM_RANKS; rank++)
4479 if (info.
4480 populated_ranks[channel][slot]
4481 [rank])
4482 config_rank(&info, s3resume,
4483 channel, slot,
4484 rank);
4485
Felix Held04be2dd2018-07-29 04:53:22 +02004486 MCHBAR8(0x243) = 0x1;
4487 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004488 }
4489
4490 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004491 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492 write_26c(0, 0x820);
4493 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004494 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495 /* end */
4496
4497 if (s3resume) {
4498 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004499 MCHBAR32(0x294 + (channel << 10)) =
4500 (info.populated_ranks_mask[channel] & 3) << 16;
4501 MCHBAR16(0x298 + (channel << 10)) =
4502 info.populated_ranks[channel][0][0] |
4503 (info.populated_ranks[channel][0][1] << 5);
4504 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004506 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004507 }
4508
Felix Held04be2dd2018-07-29 04:53:22 +02004509 MCHBAR32_AND(0xfa4, ~0x01000002);
4510 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512 /* Before training. */
4513 timestamp_add_now(103);
4514
4515 if (!s3resume)
4516 ram_training(&info);
4517
4518 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004519 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520
4521 dump_timings(&info);
4522
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523 program_modules_memory_map(&info, 0);
4524 program_total_memory_map(&info);
4525
4526 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004527 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004528 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004529 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004530 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004531 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004532 else
Felix Held04be2dd2018-07-29 04:53:22 +02004533 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004534
Felix Held04be2dd2018-07-29 04:53:22 +02004535 MCHBAR32_AND(0xfac, ~0x80000000);
4536 MCHBAR32(0xfb4) = 0x4800;
4537 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4538 MCHBAR32(0xe94) = 0x7ffff;
4539 MCHBAR32(0xfc0) = 0x80002040;
4540 MCHBAR32(0xfc4) = 0x701246;
4541 MCHBAR8_AND(0xfc8, ~0x70);
4542 MCHBAR32_OR(0xe5c, 0x1000000);
4543 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4544 MCHBAR32(0x50) = 0x700b0;
4545 MCHBAR32(0x3c) = 0x10;
4546 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4547 MCHBAR8_OR(0xff4, 0x2);
4548 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004549
Felix Held04be2dd2018-07-29 04:53:22 +02004550 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4551 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4552 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004554 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4555 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4556 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 {
4559 u32 eax;
4560
4561 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004562 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4563 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4564 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004565 }
4566
4567 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004568 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004570 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 else
Felix Held04be2dd2018-07-29 04:53:22 +02004572 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573
Felix Held04be2dd2018-07-29 04:53:22 +02004574 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575
Felix Held04be2dd2018-07-29 04:53:22 +02004576 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 else
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581 }
4582
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584
4585 {
4586 u8 al;
4587 al = 0xd;
4588 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4589 al += 2;
4590 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004591 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592 }
4593
4594 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4596 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4597 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4598 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599 }
4600 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004601 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004602 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004603 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004604 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004605 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004606 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004607 MCHBAR8_OR(0x1210, 2);
4608 MCHBAR32(0x1200) = 0x8800440;
4609 MCHBAR32(0x1204) = 0x53ff0453;
4610 MCHBAR32(0x1208) = 0x19002043;
4611 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004612
4613 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004614 MCHBAR16(0x1214) = 0x220;
4615 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004616 }
4617
Felix Held04be2dd2018-07-29 04:53:22 +02004618 MCHBAR8_OR(0x1214, 0x4);
4619 MCHBAR8(0x120c) = 0x1;
4620 MCHBAR8(0x1218) = 0x3;
4621 MCHBAR8(0x121a) = 0x3;
4622 MCHBAR8(0x121c) = 0x3;
4623 MCHBAR16(0xc14) = 0x0;
4624 MCHBAR16(0xc20) = 0x0;
4625 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626
4627 /* revision dependent here. */
4628
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630
4631 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR16_OR(0x1230, 0x8000);
4635 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636
4637 u8 bl, ebpb;
4638 u16 reg_1020;
4639
Felix Held04be2dd2018-07-29 04:53:22 +02004640 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4641 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642
Felix Held04be2dd2018-07-29 04:53:22 +02004643 MCHBAR32(0x1000) = 0x100;
4644 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
4646 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 bl = reg_1020 >> 8;
4649 ebpb = reg_1020 & 0xff;
4650 } else {
4651 ebpb = 0;
4652 bl = 8;
4653 }
4654
4655 rdmsr(0x1a2);
4656
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660
Felix Held04be2dd2018-07-29 04:53:22 +02004661 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004662
Felix Held04be2dd2018-07-29 04:53:22 +02004663 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004664 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004665 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4666 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004667 }
4668
4669 setup_heci_uma(&info);
4670
4671 if (info.uma_enabled) {
4672 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004673 MCHBAR32_OR(0x11b0, 0x4000);
4674 MCHBAR32_OR(0x11b4, 0x4000);
4675 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676
Felix Held04be2dd2018-07-29 04:53:22 +02004677 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4678 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4679 MCHBAR16_OR(0x1170, 0x1000);
4680
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004681 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004682
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004683 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004684 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004685 ;
4686 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004687 }
4688
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004689 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4690 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694 udelay(1000);
4695 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004696 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4697
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698 if (!s3resume)
4699 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004700 if (s3resume && cbmem_wasnot_inited) {
4701 u32 reg32;
4702 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004703 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004704
4705 /* Clear SLP_TYPE. */
4706 reg32 = inl(DEFAULT_PMBASE + 0x04);
4707 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4708
4709 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004710 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004711 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712}