blob: a49bd0875f2c8ad9dc7a45ce357c80b5a7a81e5f [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Angel Pons36592bf2020-09-14 18:52:44 +020064#define MRC_CACHE_VERSION 3
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Angel Ponsc2d6f5f2020-12-11 23:48:51 +0100104/*
105 * Ironlake memory I/O timings are located in scan chains, accessible
106 * through MCHBAR register groups. Each channel has a scan chain, and
107 * there's a global scan chain too. Each chain is broken into smaller
108 * sections of N bits, where N <= 32. Each section allows reading and
109 * writing a certain parameter. Each section contains N - 2 data bits
110 * and two additional bits: a Mask bit, and a Halt bit.
111 */
112
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100113/* OK */
114static void write_1d0(u32 val, u16 addr, int bits, int flag)
115{
Felix Held04be2dd2018-07-29 04:53:22 +0200116 MCHBAR32(0x1d0) = 0;
117 while (MCHBAR32(0x1d0) & 0x800000)
118 ;
119 MCHBAR32(0x1d4) =
120 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
121 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200122 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200123 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100124}
125
126/* OK */
127static u16 read_1d0(u16 addr, int split)
128{
129 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200130 MCHBAR32(0x1d0) = 0;
131 while (MCHBAR32(0x1d0) & 0x800000)
132 ;
133 MCHBAR32(0x1d0) =
134 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
135 while (MCHBAR32(0x1d0) & 0x800000)
136 ;
137 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100138 write_1d0(0, 0x33d, 0, 0);
139 write_1d0(0, 0x33d, 0, 0);
140 val &= ((1 << split) - 1);
141 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
142 return val;
143}
144
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800145static void write32p(uintptr_t addr, uint32_t val)
146{
147 write32((void *)addr, val);
148}
149
150static uint32_t read32p(uintptr_t addr)
151{
152 return read32((void *)addr);
153}
154
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100155static void sfence(void)
156{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100157 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100158}
159
160static inline u16 get_lane_offset(int slot, int rank, int lane)
161{
162 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
163 0x452 * (lane == 8);
164}
165
166static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
167{
168 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
169 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
170}
171
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100172static u32 gav_real(int line, u32 in)
173{
174 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
175 return in;
176}
177
178#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180struct raminfo {
181 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
182 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
183 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
184 u8 density[2][2]; /* [CHANNEL][SLOT] */
185 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
186 int rank_start[2][2][2];
187 u8 cas_latency;
188 u8 board_lane_delay[9];
189 u8 use_ecc;
190 u8 revision;
191 u8 max_supported_clock_speed_index;
192 u8 uma_enabled;
193 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
194 u8 silicon_revision;
195 u8 populated_ranks_mask[2];
196 u8 max_slots_used_in_channel;
197 u8 mode4030[2];
198 u16 avg4044[2];
199 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600200 unsigned int total_memory_mb;
201 unsigned int interleaved_part_mb;
202 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100203
Martin Roth468d02c2019-10-23 21:44:42 -0600204 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100205
206 struct ram_training training;
207 u32 last_500_command[2];
208
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209 u32 delay46_ps[2];
210 u32 delay54_ps[2];
211 u8 revision_flag_1;
212 u8 some_delay_1_cycle_floor;
213 u8 some_delay_2_halfcycles_ceil;
214 u8 some_delay_3_ps_rounded;
215
216 const struct ram_training *cached_training;
217};
218
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200219/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100220timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200221
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100222static void
223write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
224 int flag);
225
226/* OK */
227static u16
228read_500(struct raminfo *info, int channel, u16 addr, int split)
229{
230 u32 val;
231 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200232 MCHBAR32(0x500 + (channel << 10)) = 0;
233 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
234 ;
235 MCHBAR32(0x500 + (channel << 10)) =
236 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
237 + 0xb88 - addr);
238 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
239 ;
240 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100241 return val & ((1 << split) - 1);
242}
243
244/* OK */
245static void
246write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
247 int flag)
248{
249 if (info->last_500_command[channel] == 0x80000000) {
250 info->last_500_command[channel] = 0x40000000;
251 write_500(info, channel, 0, 0xb61, 0, 0);
252 }
Felix Held04be2dd2018-07-29 04:53:22 +0200253 MCHBAR32(0x500 + (channel << 10)) = 0;
254 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
255 ;
256 MCHBAR32(0x504 + (channel << 10)) =
257 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
258 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200259 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200260 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261}
262
263static int rw_test(int rank)
264{
265 const u32 mask = 0xf00fc33c;
266 int ok = 0xff;
267 int i;
268 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800269 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270 sfence();
271 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800272 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100273 sfence();
274 for (i = 0; i < 32; i++) {
275 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 write32p((rank << 28) | (i << 3), pat);
277 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 }
279 sfence();
280 for (i = 0; i < 32; i++) {
281 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
282 int j;
283 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800284 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 for (j = 0; j < 4; j++)
286 if (((val >> (j * 8)) & 0xff) != pat)
287 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 for (j = 0; j < 4; j++)
290 if (((val >> (j * 8)) & 0xff) != pat)
291 ok &= ~(16 << j);
292 }
293 sfence();
294 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800295 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100296 sfence();
297 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100299
300 return ok;
301}
302
303static void
304program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
305{
306 int lane;
307 for (lane = 0; lane < 8; lane++) {
308 write_500(info, channel,
309 base +
310 info->training.
311 lane_timings[2][channel][slot][rank][lane],
312 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
313 write_500(info, channel,
314 base +
315 info->training.
316 lane_timings[3][channel][slot][rank][lane],
317 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
318 }
319}
320
321static void write_26c(int channel, u16 si)
322{
Felix Held04be2dd2018-07-29 04:53:22 +0200323 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
324 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
325 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100326}
327
328static u32 get_580(int channel, u8 addr)
329{
330 u32 ret;
331 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200332 MCHBAR8(0x5ff) = 0x0;
333 MCHBAR8(0x5ff) = 0x80;
334 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
335 MCHBAR8_OR(0x580 + (channel << 10), 1);
336 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
337 ;
338 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100339 return ret;
340}
341
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100342#define NUM_CHANNELS 2
343#define NUM_SLOTS 2
344#define NUM_RANKS 2
345#define RANK_SHIFT 28
346#define CHANNEL_SHIFT 10
347
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100348static void seq9(struct raminfo *info, int channel, int slot, int rank)
349{
350 int i, lane;
351
352 for (i = 0; i < 2; i++)
353 for (lane = 0; lane < 8; lane++)
354 write_500(info, channel,
355 info->training.lane_timings[i +
356 1][channel][slot]
357 [rank][lane], get_timing_register_addr(lane,
358 i + 1,
359 slot,
360 rank),
361 9, 0);
362
363 write_1d0(1, 0x103, 6, 1);
364 for (lane = 0; lane < 8; lane++)
365 write_500(info, channel,
366 info->training.
367 lane_timings[0][channel][slot][rank][lane],
368 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
369
370 for (i = 0; i < 2; i++) {
371 for (lane = 0; lane < 8; lane++)
372 write_500(info, channel,
373 info->training.lane_timings[i +
374 1][channel][slot]
375 [rank][lane], get_timing_register_addr(lane,
376 i + 1,
377 slot,
378 rank),
379 9, 0);
380 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
381 }
382
383 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200384 MCHBAR8(0x5ff) = 0x0;
385 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100386 write_1d0(0x2, 0x142, 3, 1);
387 for (lane = 0; lane < 8; lane++) {
388 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
389 info->training.lane_timings[2][channel][slot][rank][lane] =
390 read_500(info, channel,
391 get_timing_register_addr(lane, 2, slot, rank), 9);
392 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
393 info->training.lane_timings[3][channel][slot][rank][lane] =
394 info->training.lane_timings[2][channel][slot][rank][lane] +
395 0x20;
396 }
397}
398
399static int count_ranks_in_channel(struct raminfo *info, int channel)
400{
401 int slot, rank;
402 int res = 0;
403 for (slot = 0; slot < NUM_SLOTS; slot++)
404 for (rank = 0; rank < NUM_SLOTS; rank++)
405 res += info->populated_ranks[channel][slot][rank];
406 return res;
407}
408
409static void
410config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
411{
412 int add;
413
414 write_1d0(0, 0x178, 7, 1);
415 seq9(info, channel, slot, rank);
416 program_timings(info, 0x80, channel, slot, rank);
417
418 if (channel == 0)
419 add = count_ranks_in_channel(info, 1);
420 else
421 add = 0;
422 if (!s3resume)
423 gav(rw_test(rank + add));
424 program_timings(info, 0x00, channel, slot, rank);
425 if (!s3resume)
426 gav(rw_test(rank + add));
427 if (!s3resume)
428 gav(rw_test(rank + add));
429 write_1d0(0, 0x142, 3, 1);
430 write_1d0(0, 0x103, 6, 1);
431
432 gav(get_580(channel, 0xc | (rank << 5)));
433 gav(read_1d0(0x142, 3));
434
Felix Held04be2dd2018-07-29 04:53:22 +0200435 MCHBAR8(0x5ff) = 0x0;
436 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100437}
438
439static void set_4cf(struct raminfo *info, int channel, u8 val)
440{
441 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
442 write_500(info, channel, val, 0x4cf, 4, 1);
443 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
444 write_500(info, channel, val, 0x659, 4, 1);
445 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
446 write_500(info, channel, val, 0x697, 4, 1);
447}
448
449static void set_334(int zero)
450{
451 int j, k, channel;
452 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
453 u32 vd8[2][16];
454
455 for (channel = 0; channel < NUM_CHANNELS; channel++) {
456 for (j = 0; j < 4; j++) {
457 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
458 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
459 u16 c;
460 if ((j == 0 || j == 3) && zero)
461 c = 0;
462 else if (j == 3)
463 c = 0x5f;
464 else
465 c = 0x5f5f;
466
467 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200468 MCHBAR32(0x138 + 8 * k) =
469 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100470 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200471 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100472 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200473 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100474 }
475
Felix Held22ca8cb2018-07-29 05:09:44 +0200476 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
477 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200478 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
479 zero ? 0 : (0x18191819 & lmask);
480 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
481 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
482 zero ? 0 : (a & lmask);
483 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
484 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485 }
486 }
487
Felix Held04be2dd2018-07-29 04:53:22 +0200488 MCHBAR32_OR(0x130, 1);
489 while (MCHBAR8(0x130) & 1)
490 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100491}
492
493static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
494{
495 u32 v;
496 v = read_1d0(addr, split);
497 write_1d0((v & and) | or, addr, split, flag);
498}
499
500static int find_highest_bit_set(u16 val)
501{
502 int i;
503 for (i = 15; i >= 0; i--)
504 if (val & (1 << i))
505 return i;
506 return -1;
507}
508
509static int find_lowest_bit_set32(u32 val)
510{
511 int i;
512 for (i = 0; i < 32; i++)
513 if (val & (1 << i))
514 return i;
515 return -1;
516}
517
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100518enum {
519 DEVICE_TYPE = 2,
520 MODULE_TYPE = 3,
521 DENSITY = 4,
522 RANKS_AND_DQ = 7,
523 MEMORY_BUS_WIDTH = 8,
524 TIMEBASE_DIVIDEND = 10,
525 TIMEBASE_DIVISOR = 11,
526 CYCLETIME = 12,
527
528 CAS_LATENCIES_LSB = 14,
529 CAS_LATENCIES_MSB = 15,
530 CAS_LATENCY_TIME = 16,
531 THERMAL_AND_REFRESH = 31,
532 REFERENCE_RAW_CARD_USED = 62,
533 RANK1_ADDRESS_MAPPING = 63
534};
535
536static void calculate_timings(struct raminfo *info)
537{
Martin Roth468d02c2019-10-23 21:44:42 -0600538 unsigned int cycletime;
539 unsigned int cas_latency_time;
540 unsigned int supported_cas_latencies;
541 unsigned int channel, slot;
542 unsigned int clock_speed_index;
543 unsigned int min_cas_latency;
544 unsigned int cas_latency;
545 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100546
547 /* Find common CAS latency */
548 supported_cas_latencies = 0x3fe;
549 for (channel = 0; channel < NUM_CHANNELS; channel++)
550 for (slot = 0; slot < NUM_SLOTS; slot++)
551 if (info->populated_ranks[channel][slot][0])
552 supported_cas_latencies &=
553 2 *
554 (info->
555 spd[channel][slot][CAS_LATENCIES_LSB] |
556 (info->
557 spd[channel][slot][CAS_LATENCIES_MSB] <<
558 8));
559
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100560 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100561
562 cycletime = min_cycletime[max_clock_index];
563 cas_latency_time = min_cas_latency_time[max_clock_index];
564
565 for (channel = 0; channel < NUM_CHANNELS; channel++)
566 for (slot = 0; slot < NUM_SLOTS; slot++)
567 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600568 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100569 timebase =
570 1000 *
571 info->
572 spd[channel][slot][TIMEBASE_DIVIDEND] /
573 info->spd[channel][slot][TIMEBASE_DIVISOR];
574 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100575 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100576 timebase *
577 info->spd[channel][slot][CYCLETIME]);
578 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100579 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100580 timebase *
581 info->
582 spd[channel][slot][CAS_LATENCY_TIME]);
583 }
Jacob Garber3c193822019-06-10 18:23:32 -0600584 if (cycletime > min_cycletime[0])
585 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100586 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
587 if (cycletime == min_cycletime[clock_speed_index])
588 break;
589 if (cycletime > min_cycletime[clock_speed_index]) {
590 clock_speed_index--;
591 cycletime = min_cycletime[clock_speed_index];
592 break;
593 }
594 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100595 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100596 cas_latency = 0;
597 while (supported_cas_latencies) {
598 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
599 if (cas_latency <= min_cas_latency)
600 break;
601 supported_cas_latencies &=
602 ~(1 << find_highest_bit_set(supported_cas_latencies));
603 }
604
605 if (cas_latency != min_cas_latency && clock_speed_index)
606 clock_speed_index--;
607
608 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
609 die("Couldn't configure DRAM");
610 info->clock_speed_index = clock_speed_index;
611 info->cas_latency = cas_latency;
612}
613
614static void program_base_timings(struct raminfo *info)
615{
Martin Roth468d02c2019-10-23 21:44:42 -0600616 unsigned int channel;
617 unsigned int slot, rank, lane;
618 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100619 int i;
620
621 extended_silicon_revision = info->silicon_revision;
622 if (info->silicon_revision == 0)
623 for (channel = 0; channel < NUM_CHANNELS; channel++)
624 for (slot = 0; slot < NUM_SLOTS; slot++)
625 if ((info->
626 spd[channel][slot][MODULE_TYPE] & 0xF) ==
627 3)
628 extended_silicon_revision = 4;
629
630 for (channel = 0; channel < NUM_CHANNELS; channel++) {
631 for (slot = 0; slot < NUM_SLOTS; slot++)
632 for (rank = 0; rank < NUM_SLOTS; rank++) {
633 int card_timing_2;
634 if (!info->populated_ranks[channel][slot][rank])
635 continue;
636
637 for (lane = 0; lane < 9; lane++) {
638 int tm_reg;
639 int card_timing;
640
641 card_timing = 0;
642 if ((info->
643 spd[channel][slot][MODULE_TYPE] &
644 0xF) == 3) {
645 int reference_card;
646 reference_card =
647 info->
648 spd[channel][slot]
649 [REFERENCE_RAW_CARD_USED] &
650 0x1f;
651 if (reference_card == 3)
652 card_timing =
653 u16_ffd1188[0][lane]
654 [info->
655 clock_speed_index];
656 if (reference_card == 5)
657 card_timing =
658 u16_ffd1188[1][lane]
659 [info->
660 clock_speed_index];
661 }
662
663 info->training.
664 lane_timings[0][channel][slot][rank]
665 [lane] =
666 u8_FFFD1218[info->
667 clock_speed_index];
668 info->training.
669 lane_timings[1][channel][slot][rank]
670 [lane] = 256;
671
672 for (tm_reg = 2; tm_reg < 4; tm_reg++)
673 info->training.
674 lane_timings[tm_reg]
675 [channel][slot][rank][lane]
676 =
677 u8_FFFD1240[channel]
678 [extended_silicon_revision]
679 [lane][2 * slot +
680 rank][info->
681 clock_speed_index]
682 + info->max4048[channel]
683 +
684 u8_FFFD0C78[channel]
685 [extended_silicon_revision]
686 [info->
687 mode4030[channel]][slot]
688 [rank][info->
689 clock_speed_index]
690 + card_timing;
691 for (tm_reg = 0; tm_reg < 4; tm_reg++)
692 write_500(info, channel,
693 info->training.
694 lane_timings[tm_reg]
695 [channel][slot][rank]
696 [lane],
697 get_timing_register_addr
698 (lane, tm_reg, slot,
699 rank), 9, 0);
700 }
701
702 card_timing_2 = 0;
703 if (!(extended_silicon_revision != 4
704 || (info->
705 populated_ranks_mask[channel] & 5) ==
706 5)) {
707 if ((info->
708 spd[channel][slot]
709 [REFERENCE_RAW_CARD_USED] & 0x1F)
710 == 3)
711 card_timing_2 =
712 u16_FFFE0EB8[0][info->
713 clock_speed_index];
714 if ((info->
715 spd[channel][slot]
716 [REFERENCE_RAW_CARD_USED] & 0x1F)
717 == 5)
718 card_timing_2 =
719 u16_FFFE0EB8[1][info->
720 clock_speed_index];
721 }
722
723 for (i = 0; i < 3; i++)
724 write_500(info, channel,
725 (card_timing_2 +
726 info->max4048[channel]
727 +
728 u8_FFFD0EF8[channel]
729 [extended_silicon_revision]
730 [info->
731 mode4030[channel]][info->
732 clock_speed_index]),
733 u16_fffd0c50[i][slot][rank],
734 8, 1);
735 write_500(info, channel,
736 (info->max4048[channel] +
737 u8_FFFD0C78[channel]
738 [extended_silicon_revision][info->
739 mode4030
740 [channel]]
741 [slot][rank][info->
742 clock_speed_index]),
743 u16_fffd0c70[slot][rank], 7, 1);
744 }
745 if (!info->populated_ranks_mask[channel])
746 continue;
747 for (i = 0; i < 3; i++)
748 write_500(info, channel,
749 (info->max4048[channel] +
750 info->avg4044[channel]
751 +
752 u8_FFFD17E0[channel]
753 [extended_silicon_revision][info->
754 mode4030
755 [channel]][info->
756 clock_speed_index]),
757 u16_fffd0c68[i], 8, 1);
758 }
759}
760
761static unsigned int fsbcycle_ps(struct raminfo *info)
762{
763 return 900000 / info->fsb_frequency;
764}
765
766/* The time of DDR transfer in ps. */
767static unsigned int halfcycle_ps(struct raminfo *info)
768{
769 return 3750 / (info->clock_speed_index + 3);
770}
771
772/* The time of clock cycle in ps. */
773static unsigned int cycle_ps(struct raminfo *info)
774{
775 return 2 * halfcycle_ps(info);
776}
777
778/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600779static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100780{
781 return (info->clock_speed_index + 3) * 120;
782}
783
784/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600785static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786{
787 return 100 * frequency_11(info) / 9;
788}
789
Martin Roth468d02c2019-10-23 21:44:42 -0600790static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100791{
792 return (frequency_11(info) * 2) * ps / 900000;
793}
794
Martin Roth468d02c2019-10-23 21:44:42 -0600795static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100796{
797 return (frequency_11(info)) * ns / 900;
798}
799
800static void compute_derived_timings(struct raminfo *info)
801{
Martin Roth468d02c2019-10-23 21:44:42 -0600802 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100803 int extended_silicon_revision;
804 int some_delay_1_ps;
805 int some_delay_2_ps;
806 int some_delay_2_halfcycles_ceil;
807 int some_delay_2_halfcycles_floor;
808 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100809 int some_delay_3_ps_rounded;
810 int some_delay_1_cycle_ceil;
811 int some_delay_1_cycle_floor;
812
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100813 some_delay_3_ps_rounded = 0;
814 extended_silicon_revision = info->silicon_revision;
815 if (!info->silicon_revision)
816 for (channel = 0; channel < NUM_CHANNELS; channel++)
817 for (slot = 0; slot < NUM_SLOTS; slot++)
818 if ((info->
819 spd[channel][slot][MODULE_TYPE] & 0xF) ==
820 3)
821 extended_silicon_revision = 4;
822 if (info->board_lane_delay[7] < 5)
823 info->board_lane_delay[7] = 5;
824 info->revision_flag_1 = 2;
825 if (info->silicon_revision == 2 || info->silicon_revision == 3)
826 info->revision_flag_1 = 0;
827 if (info->revision < 16)
828 info->revision_flag_1 = 0;
829
830 if (info->revision < 8)
831 info->revision_flag_1 = 0;
832 if (info->revision >= 8 && (info->silicon_revision == 0
833 || info->silicon_revision == 1))
834 some_delay_2_ps = 735;
835 else
836 some_delay_2_ps = 750;
837
838 if (info->revision >= 0x10 && (info->silicon_revision == 0
839 || info->silicon_revision == 1))
840 some_delay_1_ps = 3929;
841 else
842 some_delay_1_ps = 3490;
843
844 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
845 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
846 if (some_delay_1_ps % cycle_ps(info))
847 some_delay_1_cycle_ceil++;
848 else
849 some_delay_1_cycle_floor--;
850 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
851 if (info->revision_flag_1)
852 some_delay_2_ps = halfcycle_ps(info) >> 6;
853 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100854 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100855 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
856 375;
857 some_delay_3_ps =
858 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
859 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200860 if (some_delay_3_ps >= 150) {
861 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100862 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200863 some_delay_3_ps_rounded =
864 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
865 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100866 }
867 some_delay_2_halfcycles_ceil =
868 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
869 2 * (some_delay_1_cycle_ceil - 1);
870 if (info->revision_flag_1 && some_delay_3_ps < 150)
871 some_delay_2_halfcycles_ceil++;
872 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
873 if (info->revision < 0x10)
874 some_delay_2_halfcycles_floor =
875 some_delay_2_halfcycles_ceil - 1;
876 if (!info->revision_flag_1)
877 some_delay_2_halfcycles_floor++;
878 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
879 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
880 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
881 || (info->populated_ranks[1][0][0]
882 && info->populated_ranks[1][1][0]))
883 info->max_slots_used_in_channel = 2;
884 else
885 info->max_slots_used_in_channel = 1;
886 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200887 MCHBAR32(0x244 + (channel << 10)) =
888 ((info->revision < 8) ? 1 : 0x200) |
889 ((2 - info->max_slots_used_in_channel) << 17) |
890 (channel << 21) |
891 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 if (info->max_slots_used_in_channel == 1) {
893 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
894 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
895 } else {
896 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
897 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
898 || (count_ranks_in_channel(info, 1) ==
899 2)) ? 2 : 3;
900 }
901 for (channel = 0; channel < NUM_CHANNELS; channel++) {
902 int max_of_unk;
903 int min_of_unk_2;
904
905 int i, count;
906 int sum;
907
908 if (!info->populated_ranks_mask[channel])
909 continue;
910
911 max_of_unk = 0;
912 min_of_unk_2 = 32767;
913
914 sum = 0;
915 count = 0;
916 for (i = 0; i < 3; i++) {
917 int unk1;
918 if (info->revision < 8)
919 unk1 =
920 u8_FFFD1891[0][channel][info->
921 clock_speed_index]
922 [i];
923 else if (!
924 (info->revision >= 0x10
925 || info->revision_flag_1))
926 unk1 =
927 u8_FFFD1891[1][channel][info->
928 clock_speed_index]
929 [i];
930 else
931 unk1 = 0;
932 for (slot = 0; slot < NUM_SLOTS; slot++)
933 for (rank = 0; rank < NUM_RANKS; rank++) {
934 int a = 0;
935 int b = 0;
936
937 if (!info->
938 populated_ranks[channel][slot]
939 [rank])
940 continue;
941 if (extended_silicon_revision == 4
942 && (info->
943 populated_ranks_mask[channel] &
944 5) != 5) {
945 if ((info->
946 spd[channel][slot]
947 [REFERENCE_RAW_CARD_USED] &
948 0x1F) == 3) {
949 a = u16_ffd1178[0]
950 [info->
951 clock_speed_index];
952 b = u16_fe0eb8[0][info->
953 clock_speed_index];
954 } else
955 if ((info->
956 spd[channel][slot]
957 [REFERENCE_RAW_CARD_USED]
958 & 0x1F) == 5) {
959 a = u16_ffd1178[1]
960 [info->
961 clock_speed_index];
962 b = u16_fe0eb8[1][info->
963 clock_speed_index];
964 }
965 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100966 min_of_unk_2 = MIN(min_of_unk_2, a);
967 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100968 if (rank == 0) {
969 sum += a;
970 count++;
971 }
972 {
973 int t;
974 t = b +
975 u8_FFFD0EF8[channel]
976 [extended_silicon_revision]
977 [info->
978 mode4030[channel]][info->
979 clock_speed_index];
980 if (unk1 >= t)
981 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100982 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100983 unk1 - t);
984 }
985 }
986 {
987 int t =
988 u8_FFFD17E0[channel]
989 [extended_silicon_revision][info->
990 mode4030
991 [channel]]
992 [info->clock_speed_index] + min_of_unk_2;
993 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100994 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100995 }
996 }
997
Jacob Garber64fb4a32019-06-10 17:29:18 -0600998 if (count == 0)
999 die("No memory ranks found for channel %u\n", channel);
1000
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001001 info->avg4044[channel] = sum / count;
1002 info->max4048[channel] = max_of_unk;
1003 }
1004}
1005
1006static void jedec_read(struct raminfo *info,
1007 int channel, int slot, int rank,
1008 int total_rank, u8 addr3, unsigned int value)
1009{
1010 /* Handle mirrored mapping. */
1011 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001012 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1013 ((addr3 >> 1) & 0x10);
1014 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1015 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001016
1017 /* Handle mirrored mapping. */
1018 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1019 value =
1020 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1021 << 1);
1022
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001023 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001024
Felix Held04be2dd2018-07-29 04:53:22 +02001025 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1026 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001027
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001028 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001029}
1030
1031enum {
1032 MR1_RZQ12 = 512,
1033 MR1_RZQ2 = 64,
1034 MR1_RZQ4 = 4,
1035 MR1_ODS34OHM = 2
1036};
1037
1038enum {
1039 MR0_BT_INTERLEAVED = 8,
1040 MR0_DLL_RESET_ON = 256
1041};
1042
1043enum {
1044 MR2_RTT_WR_DISABLED = 0,
1045 MR2_RZQ2 = 1 << 10
1046};
1047
1048static void jedec_init(struct raminfo *info)
1049{
1050 int write_recovery;
1051 int channel, slot, rank;
1052 int total_rank;
1053 int dll_on;
1054 int self_refresh_temperature;
1055 int auto_self_refresh;
1056
1057 auto_self_refresh = 1;
1058 self_refresh_temperature = 1;
1059 if (info->board_lane_delay[3] <= 10) {
1060 if (info->board_lane_delay[3] <= 8)
1061 write_recovery = info->board_lane_delay[3] - 4;
1062 else
1063 write_recovery = 5;
1064 } else {
1065 write_recovery = 6;
1066 }
1067 FOR_POPULATED_RANKS {
1068 auto_self_refresh &=
1069 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1070 self_refresh_temperature &=
1071 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1072 }
1073 if (auto_self_refresh == 1)
1074 self_refresh_temperature = 0;
1075
1076 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1077 || (info->populated_ranks[0][0][0]
1078 && info->populated_ranks[0][1][0])
1079 || (info->populated_ranks[1][0][0]
1080 && info->populated_ranks[1][1][0]));
1081
1082 total_rank = 0;
1083
1084 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1085 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1086 int rzq_reg58e;
1087
1088 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1089 rzq_reg58e = 64;
1090 rtt = MR1_RZQ2;
1091 if (info->clock_speed_index != 0) {
1092 rzq_reg58e = 4;
1093 if (info->populated_ranks_mask[channel] == 3)
1094 rtt = MR1_RZQ4;
1095 }
1096 } else {
1097 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1098 rtt = MR1_RZQ12;
1099 rzq_reg58e = 64;
1100 rtt_wr = MR2_RZQ2;
1101 } else {
1102 rzq_reg58e = 4;
1103 rtt = MR1_RZQ4;
1104 }
1105 }
1106
Felix Held04be2dd2018-07-29 04:53:22 +02001107 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1108 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1109 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1110 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1111 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001112
1113 for (slot = 0; slot < NUM_SLOTS; slot++)
1114 for (rank = 0; rank < NUM_RANKS; rank++)
1115 if (info->populated_ranks[channel][slot][rank]) {
1116 jedec_read(info, channel, slot, rank,
1117 total_rank, 0x28,
1118 rtt_wr | (info->
1119 clock_speed_index
1120 << 3)
1121 | (auto_self_refresh << 6) |
1122 (self_refresh_temperature <<
1123 7));
1124 jedec_read(info, channel, slot, rank,
1125 total_rank, 0x38, 0);
1126 jedec_read(info, channel, slot, rank,
1127 total_rank, 0x18,
1128 rtt | MR1_ODS34OHM);
1129 jedec_read(info, channel, slot, rank,
1130 total_rank, 6,
1131 (dll_on << 12) |
1132 (write_recovery << 9)
1133 | ((info->cas_latency - 4) <<
1134 4) | MR0_BT_INTERLEAVED |
1135 MR0_DLL_RESET_ON);
1136 total_rank++;
1137 }
1138 }
1139}
1140
1141static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1142{
Martin Roth468d02c2019-10-23 21:44:42 -06001143 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001144 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1145 unsigned int channel_0_non_interleaved;
1146
1147 FOR_ALL_RANKS {
1148 if (info->populated_ranks[channel][slot][rank]) {
1149 total_mb[channel] +=
1150 pre_jedec ? 256 : (256 << info->
1151 density[channel][slot] >> info->
1152 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001153 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1154 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1155 (info->is_x16_module[channel][slot] |
1156 ((info->density[channel][slot] + 1) << 1))) |
1157 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001158 }
Felix Held04be2dd2018-07-29 04:53:22 +02001159 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1160 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 }
1162
1163 info->total_memory_mb = total_mb[0] + total_mb[1];
1164
1165 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001166 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 info->non_interleaved_part_mb =
1168 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1169 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001170 MCHBAR32(0x100) = channel_0_non_interleaved |
1171 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001173 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174}
1175
1176static void program_board_delay(struct raminfo *info)
1177{
1178 int cas_latency_shift;
1179 int some_delay_ns;
1180 int some_delay_3_half_cycles;
1181
Martin Roth468d02c2019-10-23 21:44:42 -06001182 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183 int high_multiplier;
1184 int lane_3_delay;
1185 int cas_latency_derived;
1186
1187 high_multiplier = 0;
1188 some_delay_ns = 200;
1189 some_delay_3_half_cycles = 4;
1190 cas_latency_shift = info->silicon_revision == 0
1191 || info->silicon_revision == 1 ? 1 : 0;
1192 if (info->revision < 8) {
1193 some_delay_ns = 600;
1194 cas_latency_shift = 0;
1195 }
1196 {
1197 int speed_bit;
1198 speed_bit =
1199 ((info->clock_speed_index > 1
1200 || (info->silicon_revision != 2
1201 && info->silicon_revision != 3))) ^ (info->revision >=
1202 0x10);
1203 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1204 3, 1);
1205 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1206 3, 1);
1207 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1208 && (info->silicon_revision == 2
1209 || info->silicon_revision == 3))
1210 rmw_1d0(0x116, 5, 2, 4, 1);
1211 }
Felix Held04be2dd2018-07-29 04:53:22 +02001212 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1213 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001214
Felix Held04be2dd2018-07-29 04:53:22 +02001215 MCHBAR8(0x124) = info->board_lane_delay[4] +
1216 ((frequency_01(info) + 999) / 1000);
1217 MCHBAR16(0x125) = 0x1360;
1218 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001219 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001220 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001221 high_multiplier = 1;
1222 some_delay_2_half_cycles = ps_to_halfcycles(info,
1223 ((3 *
1224 fsbcycle_ps(info))
1225 >> 1) +
1226 (halfcycle_ps(info)
1227 *
1228 reg178_min[info->
1229 clock_speed_index]
1230 >> 6)
1231 +
1232 4 *
1233 halfcycle_ps(info)
1234 + 2230);
1235 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001236 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001237 (frequency_11(info) * 2) * (28 -
1238 some_delay_2_half_cycles) /
1239 (frequency_11(info) * 2 -
1240 4 * (info->fsb_frequency))) >> 3, 7);
1241 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001242 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001243 some_delay_3_half_cycles = 3;
1244 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001245 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1246 MCHBAR32(0x224 + (channel << 10)) =
1247 (info->max_slots_used_in_channel - 1) |
1248 ((info->cas_latency - 5 - info->clock_speed_index)
1249 << 21) | ((info->max_slots_used_in_channel +
1250 info->cas_latency - cas_latency_shift - 4) << 16) |
1251 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1252 ((info->cas_latency - info->clock_speed_index +
1253 info->max_slots_used_in_channel - 6) << 8);
1254 MCHBAR32(0x228 + (channel << 10)) =
1255 info->max_slots_used_in_channel;
1256 MCHBAR8(0x239 + (channel << 10)) = 32;
1257 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1258 (some_delay_3_half_cycles << 25) | 0x840000;
1259 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1260 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1261 MCHBAR32(0x24c + (channel << 10)) =
1262 ((!!info->clock_speed_index) << 17) |
1263 (((2 + info->clock_speed_index -
1264 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001265
Felix Held04be2dd2018-07-29 04:53:22 +02001266 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1267 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1268 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001269
1270 write_500(info, channel,
1271 ((!info->populated_ranks[channel][1][1])
1272 | (!info->populated_ranks[channel][1][0] << 1)
1273 | (!info->populated_ranks[channel][0][1] << 2)
1274 | (!info->populated_ranks[channel][0][0] << 3)),
1275 0x4c9, 4, 1);
1276 }
1277
Felix Held22ca8cb2018-07-29 05:09:44 +02001278 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279 {
1280 u8 freq_divisor = 2;
1281 if (info->fsb_frequency == frequency_11(info))
1282 freq_divisor = 3;
1283 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1284 freq_divisor = 1;
1285 else
1286 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001287 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001288 }
1289
1290 if (info->board_lane_delay[3] <= 10) {
1291 if (info->board_lane_delay[3] <= 8)
1292 lane_3_delay = info->board_lane_delay[3];
1293 else
1294 lane_3_delay = 10;
1295 } else {
1296 lane_3_delay = 12;
1297 }
1298 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1299 if (info->clock_speed_index > 1)
1300 cas_latency_derived++;
1301 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001302 MCHBAR32(0x240 + (channel << 10)) =
1303 ((info->clock_speed_index == 0) * 0x11000) |
1304 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1305 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001306 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1307 0x609, 6, 1);
1308 write_500(info, channel,
1309 info->clock_speed_index + 2 * info->cas_latency - 7,
1310 0x601, 6, 1);
1311
Felix Held04be2dd2018-07-29 04:53:22 +02001312 MCHBAR32(0x250 + (channel << 10)) =
1313 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1314 (info->board_lane_delay[7] << 2) |
1315 (info->board_lane_delay[4] << 16) |
1316 (info->board_lane_delay[1] << 25) |
1317 (info->board_lane_delay[1] << 29) | 1;
1318 MCHBAR32(0x254 + (channel << 10)) =
1319 (info->board_lane_delay[1] >> 3) |
1320 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1321 0x80 | (info->board_lane_delay[6] << 1) |
1322 (info->board_lane_delay[2] << 28) |
1323 (cas_latency_derived << 16) | 0x4700000;
1324 MCHBAR32(0x258 + (channel << 10)) =
1325 ((info->board_lane_delay[5] + info->clock_speed_index +
1326 9) << 12) | ((info->clock_speed_index -
1327 info->cas_latency + 12) << 8) |
1328 (info->board_lane_delay[2] << 17) |
1329 (info->board_lane_delay[4] << 24) | 0x47;
1330 MCHBAR32(0x25c + (channel << 10)) =
1331 (info->board_lane_delay[1] << 1) |
1332 (info->board_lane_delay[0] << 8) | 0x1da50000;
1333 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1334 MCHBAR8(0x5f8 + (channel << 10)) =
1335 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001336 }
1337
1338 program_modules_memory_map(info, 1);
1339
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001340 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001341 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1342 MCHBAR16_OR(0x612, 0x100);
1343 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001344 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001345 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001346 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001347 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001348 }
1349}
1350
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001351#define DEFAULT_PCI_MMIO_SIZE 2048
1352#define HOST_BRIDGE PCI_DEVFN(0, 0)
1353
1354static unsigned int get_mmio_size(void)
1355{
1356 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001357 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001358
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001359 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001360 if (dev)
1361 cfg = dev->chip_info;
1362
1363 /* If this is zero, it just means devicetree.cb didn't set it */
1364 if (!cfg || cfg->pci_mmio_size == 0)
1365 return DEFAULT_PCI_MMIO_SIZE;
1366 else
1367 return cfg->pci_mmio_size;
1368}
1369
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001370static void program_total_memory_map(struct raminfo *info)
1371{
Angel Pons9333b742020-07-22 16:04:15 +02001372 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001373 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001374 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001375 unsigned int uma_base_igd;
1376 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001377 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378 int memory_remap;
1379 unsigned int memory_map[8];
1380 int i;
1381 unsigned int current_limit;
1382 unsigned int tseg_base;
1383 int uma_size_igd = 0, uma_size_gtt = 0;
1384
1385 memset(memory_map, 0, sizeof(memory_map));
1386
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001388 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001389 gav(t);
1390 const int uma_sizes_gtt[16] =
1391 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1392 /* Igd memory */
1393 const int uma_sizes_igd[16] = {
1394 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1395 256, 512
1396 };
1397
1398 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1399 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1400 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001402 mmio_size = get_mmio_size();
1403
Angel Pons9333b742020-07-22 16:04:15 +02001404 tom = info->total_memory_mb;
1405 if (tom == 4096)
1406 tom = 4032;
1407 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1408 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1409 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001410 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001411 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001413 remap_base = MAX(4096, touud);
1414 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415 }
Angel Pons9333b742020-07-22 16:04:15 +02001416 if (touud > 4096)
1417 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418 quickpath_reserved = 0;
1419
Angel Pons3ab19b32020-07-22 16:29:54 +02001420 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001421
Jacob Garber975a7e32019-06-10 16:32:47 -06001422 gav(t);
1423
1424 if (t & 0x800) {
1425 u32 shift = t >> 20;
1426 if (shift == 0)
1427 die("Quickpath value is 0\n");
1428 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001430
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001431 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001432 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001433
Angel Pons9333b742020-07-22 16:04:15 +02001434 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001435 uma_base_gtt = uma_base_igd - uma_size_gtt;
1436 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1437 if (!memory_remap)
1438 tseg_base -= quickpath_reserved;
1439 tseg_base = ALIGN_DOWN(tseg_base, 8);
1440
Angel Pons16fe1e02020-07-22 16:12:33 +02001441 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1442 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001444 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1445 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001447 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448
1449 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001450 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1451 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001453 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454
1455 current_limit = 0;
1456 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1457 memory_map[1] = 4096;
1458 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001459 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001460 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1462 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001463 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464 }
1465}
1466
1467static void collect_system_info(struct raminfo *info)
1468{
1469 u32 capid0[3];
1470 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001471 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472
1473 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001474 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1475 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477 if (!info->memory_reserved_for_heci_mb) {
1478 /* Wait for ME to be ready */
1479 intel_early_me_init();
1480 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1481 }
1482
1483 for (i = 0; i < 3; i++)
1484 gav(capid0[i] =
Angel Pons16fe1e02020-07-22 16:12:33 +02001485 pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2)));
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001486 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1488
1489 if ((capid0[1] >> 11) & 1)
1490 info->uma_enabled = 0;
1491 else
1492 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001493 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1495 info->silicon_revision = 0;
1496
1497 if (capid0[2] & 2) {
1498 info->silicon_revision = 0;
1499 info->max_supported_clock_speed_index = 2;
1500 for (channel = 0; channel < NUM_CHANNELS; channel++)
1501 if (info->populated_ranks[channel][0][0]
1502 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1503 3) {
1504 info->silicon_revision = 2;
1505 info->max_supported_clock_speed_index = 1;
1506 }
1507 } else {
1508 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1509 case 1:
1510 case 2:
1511 info->silicon_revision = 3;
1512 break;
1513 case 3:
1514 info->silicon_revision = 0;
1515 break;
1516 case 0:
1517 info->silicon_revision = 2;
1518 break;
1519 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001520 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001521 case 0x40:
1522 info->silicon_revision = 0;
1523 break;
1524 case 0x48:
1525 info->silicon_revision = 1;
1526 break;
1527 }
1528 }
1529}
1530
1531static void write_training_data(struct raminfo *info)
1532{
1533 int tm, channel, slot, rank, lane;
1534 if (info->revision < 8)
1535 return;
1536
1537 for (tm = 0; tm < 4; tm++)
1538 for (channel = 0; channel < NUM_CHANNELS; channel++)
1539 for (slot = 0; slot < NUM_SLOTS; slot++)
1540 for (rank = 0; rank < NUM_RANKS; rank++)
1541 for (lane = 0; lane < 9; lane++)
1542 write_500(info, channel,
1543 info->
1544 cached_training->
1545 lane_timings[tm]
1546 [channel][slot][rank]
1547 [lane],
1548 get_timing_register_addr
1549 (lane, tm, slot,
1550 rank), 9, 0);
1551 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1552 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1553}
1554
1555static void dump_timings(struct raminfo *info)
1556{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001558 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001560 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001561 slot, rank);
1562 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001563 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001564 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001565 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001566 read_500(info, channel,
1567 get_timing_register_addr
1568 (lane, i, slot, rank),
1569 9),
1570 info->training.
1571 lane_timings[i][channel][slot][rank]
1572 [lane]);
1573 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001574 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575 }
1576 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001577 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001579 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581}
1582
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001583/* Read timings and other registers that need to be restored verbatim and
1584 put them to CBMEM.
1585 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586static void save_timings(struct raminfo *info)
1587{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589 int channel, slot, rank, lane, i;
1590
1591 train = info->training;
1592 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1593 for (i = 0; i < 4; i++)
1594 train.lane_timings[i][channel][slot][rank][lane] =
1595 read_500(info, channel,
1596 get_timing_register_addr(lane, i, slot,
1597 rank), 9);
1598 train.reg_178 = read_1d0(0x178, 7);
1599 train.reg_10b = read_1d0(0x10b, 6);
1600
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001601 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1602 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001603 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001604 train.reg274265[channel][0] = reg32 >> 16;
1605 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001606 train.reg274265[channel][2] =
1607 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001608 }
Felix Held04be2dd2018-07-29 04:53:22 +02001609 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1610 train.reg_6dc = MCHBAR32(0x6dc);
1611 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612
Arthur Heymansb3282092019-04-14 17:53:28 +02001613 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1614 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001615
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001616 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001617 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1618 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001619}
1620
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621static const struct ram_training *get_cached_training(void)
1622{
Shelley Chenad9cd682020-07-23 16:10:52 -07001623 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1624 MRC_CACHE_VERSION,
1625 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001627
1628/* FIXME: add timeout. */
1629static void wait_heci_ready(void)
1630{
Felix Held04be2dd2018-07-29 04:53:22 +02001631 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1632 ;
Angel Ponseb537932020-09-14 19:18:11 +02001633
1634 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001635}
1636
1637/* FIXME: add timeout. */
1638static void wait_heci_cb_avail(int len)
1639{
1640 union {
1641 struct mei_csr csr;
1642 u32 raw;
1643 } csr;
1644
Felix Held22ca8cb2018-07-29 05:09:44 +02001645 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1646 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647
Angel Ponseb537932020-09-14 19:18:11 +02001648 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001649 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001650 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1651 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001652}
1653
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001654static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001655{
1656 int len = (head->length + 3) / 4;
1657 int i;
1658
1659 wait_heci_cb_avail(len + 1);
1660
1661 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001662 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001664 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001666 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1667 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668}
1669
Angel Ponseb537932020-09-14 19:18:11 +02001670static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671{
1672 struct mei_header head;
1673 int maxlen;
1674
1675 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001676 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001677
1678 while (len) {
1679 int cur = len;
1680 if (cur > maxlen) {
1681 cur = maxlen;
1682 head.is_complete = 0;
1683 } else
1684 head.is_complete = 1;
1685 head.length = cur;
1686 head.reserved = 0;
1687 head.client_address = clientaddress;
1688 head.host_address = hostaddress;
1689 send_heci_packet(&head, (u32 *) msg);
1690 len -= cur;
1691 msg += cur;
1692 }
1693}
1694
1695/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001696static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001697{
1698 union {
1699 struct mei_csr csr;
1700 u32 raw;
1701 } csr;
1702 int i = 0;
1703
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001704 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001706 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001707 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1708
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001709 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001711 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001712 *packet_size = 0;
1713 return 0;
1714 }
Angel Ponseb537932020-09-14 19:18:11 +02001715 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 *packet_size = 0;
1717 return -1;
1718 }
1719
Angel Ponseb537932020-09-14 19:18:11 +02001720 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001721 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001722 } while (((head->length + 3) >> 2) >
1723 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724
1725 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001726 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727 *packet_size = head->length;
1728 if (!csr.csr.ready)
1729 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 return 0;
1732}
1733
1734/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001735static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001736{
1737 struct mei_header head;
1738 int current_position;
1739
1740 current_position = 0;
1741 while (1) {
1742 u32 current_size;
1743 current_size = *message_size - current_position;
1744 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001745 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746 &current_size) == -1)
1747 break;
1748 if (!current_size)
1749 break;
1750 current_position += current_size;
1751 if (head.is_complete) {
1752 *message_size = current_position;
1753 return 0;
1754 }
1755
1756 if (current_position >= *message_size)
1757 break;
1758 }
1759 *message_size = 0;
1760 return -1;
1761}
1762
Angel Pons55f11e22020-09-14 19:06:53 +02001763static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001764{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001765 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001766 u8 group_id;
1767 u8 command;
1768 u8 reserved;
1769 u8 result;
1770 u8 field2;
1771 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001772 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001773
1774 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1775 reply.command = 0;
1776
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001777 struct uma_message {
1778 u8 group_id;
1779 u8 cmd;
1780 u8 reserved;
1781 u8 result;
1782 u32 c2;
1783 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001784 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001785 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001786 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001787 .group_id = 0,
1788 .cmd = MKHI_SET_UMA,
1789 .reserved = 0,
1790 .result = 0,
1791 .c2 = 0x82,
1792 .heci_uma_addr = heci_uma_addr,
1793 .heci_uma_size = heci_uma_size,
1794 .c3 = 0,
1795 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001796 u32 reply_size;
1797
Angel Ponseb537932020-09-14 19:18:11 +02001798 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001799
1800 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001801 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001802 return;
1803
1804 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1805 die("HECI init failed\n");
1806}
1807
1808static void setup_heci_uma(struct raminfo *info)
1809{
Angel Pons298d34d2020-09-14 18:58:53 +02001810 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001811 return;
1812
Angel Pons36592bf2020-09-14 18:52:44 +02001813 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001814 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001815 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001816 info->memory_reserved_for_heci_mb)) << 20;
1817
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001818 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001819 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001820 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001821 write32(DEFAULT_RCBA + 0x14, read32(DEFAULT_RCBA + 0x14) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001822 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001823 write32(DEFAULT_RCBA + 0x20, read32(DEFAULT_RCBA + 0x20) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001824 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001825 write32(DEFAULT_RCBA + 0x30, read32(DEFAULT_RCBA + 0x30) & ~0x80);
Angel Pons3b264d02020-09-15 00:25:49 +02001826 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponseb537932020-09-14 19:18:11 +02001827 write32(DEFAULT_RCBA + 0x40, read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828
Angel Ponseb537932020-09-14 19:18:11 +02001829 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001830 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001831
Felix Held04be2dd2018-07-29 04:53:22 +02001832 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
Angel Pons3b264d02020-09-15 00:25:49 +02001833 DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001834 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835 }
1836
Felix Held04be2dd2018-07-29 04:53:22 +02001837 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838
Angel Pons55f11e22020-09-14 19:06:53 +02001839 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001841 pci_write_config32(HECIDEV, 0x10, 0x0);
1842 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001843}
1844
1845static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1846{
1847 int ranks_in_channel;
1848 ranks_in_channel = info->populated_ranks[channel][0][0]
1849 + info->populated_ranks[channel][0][1]
1850 + info->populated_ranks[channel][1][0]
1851 + info->populated_ranks[channel][1][1];
1852
1853 /* empty channel */
1854 if (ranks_in_channel == 0)
1855 return 1;
1856
1857 if (ranks_in_channel != ranks)
1858 return 0;
1859 /* single slot */
1860 if (info->populated_ranks[channel][0][0] !=
1861 info->populated_ranks[channel][1][0])
1862 return 1;
1863 if (info->populated_ranks[channel][0][1] !=
1864 info->populated_ranks[channel][1][1])
1865 return 1;
1866 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1867 return 0;
1868 if (info->density[channel][0] != info->density[channel][1])
1869 return 0;
1870 return 1;
1871}
1872
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001873static void read_4090(struct raminfo *info)
1874{
1875 int i, channel, slot, rank, lane;
1876 for (i = 0; i < 2; i++)
1877 for (slot = 0; slot < NUM_SLOTS; slot++)
1878 for (rank = 0; rank < NUM_RANKS; rank++)
1879 for (lane = 0; lane < 9; lane++)
1880 info->training.
1881 lane_timings[0][i][slot][rank][lane]
1882 = 32;
1883
1884 for (i = 1; i < 4; i++)
1885 for (channel = 0; channel < NUM_CHANNELS; channel++)
1886 for (slot = 0; slot < NUM_SLOTS; slot++)
1887 for (rank = 0; rank < NUM_RANKS; rank++)
1888 for (lane = 0; lane < 9; lane++) {
1889 info->training.
1890 lane_timings[i][channel]
1891 [slot][rank][lane] =
1892 read_500(info, channel,
1893 get_timing_register_addr
1894 (lane, i, slot,
1895 rank), 9)
1896 + (i == 1) * 11; // !!!!
1897 }
1898
1899}
1900
1901static u32 get_etalon2(int flip, u32 addr)
1902{
1903 const u16 invmask[] = {
1904 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1905 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1906 };
1907 u32 ret;
1908 u32 comp4 = addr / 480;
1909 addr %= 480;
1910 u32 comp1 = addr & 0xf;
1911 u32 comp2 = (addr >> 4) & 1;
1912 u32 comp3 = addr >> 5;
1913
1914 if (comp4)
1915 ret = 0x1010101 << (comp4 - 1);
1916 else
1917 ret = 0;
1918 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1919 ret = ~ret;
1920
1921 return ret;
1922}
1923
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001924static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001925{
1926 msr_t msr = {.lo = 0, .hi = 0 };
1927
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001928 wrmsr(MTRR_PHYS_BASE(3), msr);
1929 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001930}
1931
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001932static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001933{
1934 msr_t msr;
1935 msr.lo = base | MTRR_TYPE_WRPROT;
1936 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001937 wrmsr(MTRR_PHYS_BASE(3), msr);
1938 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001939 & 0xffffffff);
1940 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001941 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001942}
1943
1944static void flush_cache(u32 start, u32 size)
1945{
1946 u32 end;
1947 u32 addr;
1948
1949 end = start + (ALIGN_DOWN(size + 4096, 4096));
1950 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001951 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001952}
1953
1954static void clear_errors(void)
1955{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001956 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001957}
1958
1959static void write_testing(struct raminfo *info, int totalrank, int flip)
1960{
1961 int nwrites = 0;
1962 /* in 8-byte units. */
1963 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001964 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001965
Patrick Rudolph819c2062019-11-29 19:27:37 +01001966 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967 for (offset = 0; offset < 9 * 480; offset += 2) {
1968 write32(base + offset * 8, get_etalon2(flip, offset));
1969 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1970 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1971 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1972 nwrites += 4;
1973 if (nwrites >= 320) {
1974 clear_errors();
1975 nwrites = 0;
1976 }
1977 }
1978}
1979
1980static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1981{
1982 u8 failmask = 0;
1983 int i;
1984 int comp1, comp2, comp3;
1985 u32 failxor[2] = { 0, 0 };
1986
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001987 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001988
1989 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1990 for (comp1 = 0; comp1 < 4; comp1++)
1991 for (comp2 = 0; comp2 < 60; comp2++) {
1992 u32 re[4];
1993 u32 curroffset =
1994 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1995 read128((total_rank << 28) | (curroffset << 3),
1996 (u64 *) re);
1997 failxor[0] |=
1998 get_etalon2(flip, curroffset) ^ re[0];
1999 failxor[1] |=
2000 get_etalon2(flip, curroffset) ^ re[1];
2001 failxor[0] |=
2002 get_etalon2(flip, curroffset | 1) ^ re[2];
2003 failxor[1] |=
2004 get_etalon2(flip, curroffset | 1) ^ re[3];
2005 }
2006 for (i = 0; i < 8; i++)
2007 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2008 failmask |= 1 << i;
2009 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002010 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002011 flush_cache((total_rank << 28), 1728 * 5 * 4);
2012 return failmask;
2013}
2014
2015const u32 seed1[0x18] = {
2016 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2017 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2018 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2019 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2020 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2021 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2022};
2023
2024static u32 get_seed2(int a, int b)
2025{
2026 const u32 seed2[5] = {
2027 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2028 0x5b6db6db,
2029 };
2030 u32 r;
2031 r = seed2[(a + (a >= 10)) / 5];
2032 return b ? ~r : r;
2033}
2034
2035static int make_shift(int comp2, int comp5, int x)
2036{
2037 const u8 seed3[32] = {
2038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2039 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2040 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2041 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2042 };
2043
2044 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2045}
2046
2047static u32 get_etalon(int flip, u32 addr)
2048{
2049 u32 mask_byte = 0;
2050 int comp1 = (addr >> 1) & 1;
2051 int comp2 = (addr >> 3) & 0x1f;
2052 int comp3 = (addr >> 8) & 0xf;
2053 int comp4 = (addr >> 12) & 0xf;
2054 int comp5 = (addr >> 16) & 0x1f;
2055 u32 mask_bit = ~(0x10001 << comp3);
2056 u32 part1;
2057 u32 part2;
2058 int byte;
2059
2060 part2 =
2061 ((seed1[comp5] >>
2062 make_shift(comp2, comp5,
2063 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2064 part1 =
2065 ((seed1[comp5] >>
2066 make_shift(comp2, comp5,
2067 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2068
2069 for (byte = 0; byte < 4; byte++)
2070 if ((get_seed2(comp5, comp4) >>
2071 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2072 mask_byte |= 0xff << (8 * byte);
2073
2074 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2075 (comp3 + 16));
2076}
2077
2078static void
2079write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2080 char flip)
2081{
2082 int i;
2083 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002084 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2085 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002086}
2087
2088static u8
2089check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2090 char flip)
2091{
2092 u8 failmask = 0;
2093 u32 failxor[2];
2094 int i;
2095 int comp1, comp2, comp3;
2096
2097 failxor[0] = 0;
2098 failxor[1] = 0;
2099
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002100 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002101 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2102 for (comp1 = 0; comp1 < 16; comp1++)
2103 for (comp2 = 0; comp2 < 64; comp2++) {
2104 u32 addr =
2105 (totalrank << 28) | (region << 25) | (block
2106 << 16)
2107 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2108 2);
2109 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002110 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002111 }
2112 for (i = 0; i < 8; i++)
2113 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2114 failmask |= 1 << i;
2115 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002116 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002117 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2118 return failmask;
2119}
2120
2121static int check_bounded(unsigned short *vals, u16 bound)
2122{
2123 int i;
2124
2125 for (i = 0; i < 8; i++)
2126 if (vals[i] < bound)
2127 return 0;
2128 return 1;
2129}
2130
2131enum state {
2132 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2133};
2134
2135static int validate_state(enum state *in)
2136{
2137 int i;
2138 for (i = 0; i < 8; i++)
2139 if (in[i] != COMPLETE)
2140 return 0;
2141 return 1;
2142}
2143
2144static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002145do_fsm(enum state *state, u16 *counter,
2146 u8 fail_mask, int margin, int uplimit,
2147 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002148{
2149 int lane;
2150
2151 for (lane = 0; lane < 8; lane++) {
2152 int is_fail = (fail_mask >> lane) & 1;
2153 switch (state[lane]) {
2154 case BEFORE_USABLE:
2155 if (!is_fail) {
2156 counter[lane] = 1;
2157 state[lane] = AT_USABLE;
2158 break;
2159 }
2160 counter[lane] = 0;
2161 state[lane] = BEFORE_USABLE;
2162 break;
2163 case AT_USABLE:
2164 if (!is_fail) {
2165 ++counter[lane];
2166 if (counter[lane] >= margin) {
2167 state[lane] = AT_MARGIN;
2168 res_low[lane] = val - margin + 1;
2169 break;
2170 }
2171 state[lane] = 1;
2172 break;
2173 }
2174 counter[lane] = 0;
2175 state[lane] = BEFORE_USABLE;
2176 break;
2177 case AT_MARGIN:
2178 if (is_fail) {
2179 state[lane] = COMPLETE;
2180 res_high[lane] = val - 1;
2181 } else {
2182 counter[lane]++;
2183 state[lane] = AT_MARGIN;
2184 if (val == uplimit) {
2185 state[lane] = COMPLETE;
2186 res_high[lane] = uplimit;
2187 }
2188 }
2189 break;
2190 case COMPLETE:
2191 break;
2192 }
2193 }
2194}
2195
2196static void
2197train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2198 u8 total_rank, u8 reg_178, int first_run, int niter,
2199 timing_bounds_t * timings)
2200{
2201 int lane;
2202 enum state state[8];
2203 u16 count[8];
2204 u8 lower_usable[8];
2205 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002206 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002207 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002208 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002209
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002210 for (i = 0; i < 8; i++)
2211 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002212
2213 if (!first_run) {
2214 int is_all_ok = 1;
2215 for (lane = 0; lane < 8; lane++)
2216 if (timings[reg_178][channel][slot][rank][lane].
2217 smallest ==
2218 timings[reg_178][channel][slot][rank][lane].
2219 largest) {
2220 timings[reg_178][channel][slot][rank][lane].
2221 smallest = 0;
2222 timings[reg_178][channel][slot][rank][lane].
2223 largest = 0;
2224 is_all_ok = 0;
2225 }
2226 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002227 for (i = 0; i < 8; i++)
2228 state[i] = COMPLETE;
2229 }
2230 }
2231
2232 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2233 u8 failmask = 0;
2234 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2235 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2236 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002237 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002238 do_fsm(state, count, failmask, 5, 47, lower_usable,
2239 upper_usable, reg1b3);
2240 }
2241
2242 if (reg1b3) {
2243 write_1d0(0, 0x1b3, 6, 1);
2244 write_1d0(0, 0x1a3, 6, 1);
2245 for (lane = 0; lane < 8; lane++) {
2246 if (state[lane] == COMPLETE) {
2247 timings[reg_178][channel][slot][rank][lane].
2248 smallest =
2249 lower_usable[lane] +
2250 (info->training.
2251 lane_timings[0][channel][slot][rank][lane]
2252 & 0x3F) - 32;
2253 timings[reg_178][channel][slot][rank][lane].
2254 largest =
2255 upper_usable[lane] +
2256 (info->training.
2257 lane_timings[0][channel][slot][rank][lane]
2258 & 0x3F) - 32;
2259 }
2260 }
2261 }
2262
2263 if (!first_run) {
2264 for (lane = 0; lane < 8; lane++)
2265 if (state[lane] == COMPLETE) {
2266 write_500(info, channel,
2267 timings[reg_178][channel][slot][rank]
2268 [lane].smallest,
2269 get_timing_register_addr(lane, 0,
2270 slot, rank),
2271 9, 1);
2272 write_500(info, channel,
2273 timings[reg_178][channel][slot][rank]
2274 [lane].smallest +
2275 info->training.
2276 lane_timings[1][channel][slot][rank]
2277 [lane]
2278 -
2279 info->training.
2280 lane_timings[0][channel][slot][rank]
2281 [lane], get_timing_register_addr(lane,
2282 1,
2283 slot,
2284 rank),
2285 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002286 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002287 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002288 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002289
2290 do {
2291 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002292 for (i = 0; i < niter; i++) {
2293 if (failmask == 0xFF)
2294 break;
2295 failmask |=
2296 check_testing_type2(info, total_rank, 2, i,
2297 0);
2298 failmask |=
2299 check_testing_type2(info, total_rank, 3, i,
2300 1);
2301 }
Felix Held04be2dd2018-07-29 04:53:22 +02002302 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002303 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002304 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002305 if ((1 << lane) & failmask) {
2306 if (timings[reg_178][channel]
2307 [slot][rank][lane].
2308 largest <=
2309 timings[reg_178][channel]
2310 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002311 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002312 [lane] = -1;
2313 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002314 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002315 [lane] = 0;
2316 timings[reg_178]
2317 [channel][slot]
2318 [rank][lane].
2319 smallest++;
2320 write_500(info, channel,
2321 timings
2322 [reg_178]
2323 [channel]
2324 [slot][rank]
2325 [lane].
2326 smallest,
2327 get_timing_register_addr
2328 (lane, 0,
2329 slot, rank),
2330 9, 1);
2331 write_500(info, channel,
2332 timings
2333 [reg_178]
2334 [channel]
2335 [slot][rank]
2336 [lane].
2337 smallest +
2338 info->
2339 training.
2340 lane_timings
2341 [1][channel]
2342 [slot][rank]
2343 [lane]
2344 -
2345 info->
2346 training.
2347 lane_timings
2348 [0][channel]
2349 [slot][rank]
2350 [lane],
2351 get_timing_register_addr
2352 (lane, 1,
2353 slot, rank),
2354 9, 1);
2355 }
2356 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002357 num_successfully_checked[lane]
2358 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002359 }
2360 }
Felix Held04be2dd2018-07-29 04:53:22 +02002361 while (!check_bounded(num_successfully_checked, 2))
2362 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363
2364 for (lane = 0; lane < 8; lane++)
2365 if (state[lane] == COMPLETE) {
2366 write_500(info, channel,
2367 timings[reg_178][channel][slot][rank]
2368 [lane].largest,
2369 get_timing_register_addr(lane, 0,
2370 slot, rank),
2371 9, 1);
2372 write_500(info, channel,
2373 timings[reg_178][channel][slot][rank]
2374 [lane].largest +
2375 info->training.
2376 lane_timings[1][channel][slot][rank]
2377 [lane]
2378 -
2379 info->training.
2380 lane_timings[0][channel][slot][rank]
2381 [lane], get_timing_register_addr(lane,
2382 1,
2383 slot,
2384 rank),
2385 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002386 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002387 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002388 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002389
2390 do {
2391 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002392 for (i = 0; i < niter; i++) {
2393 if (failmask == 0xFF)
2394 break;
2395 failmask |=
2396 check_testing_type2(info, total_rank, 2, i,
2397 0);
2398 failmask |=
2399 check_testing_type2(info, total_rank, 3, i,
2400 1);
2401 }
2402
Felix Held04be2dd2018-07-29 04:53:22 +02002403 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002404 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002405 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002406 if ((1 << lane) & failmask) {
2407 if (timings[reg_178][channel]
2408 [slot][rank][lane].
2409 largest <=
2410 timings[reg_178][channel]
2411 [slot][rank][lane].
2412 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002413 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002414 [lane] = -1;
2415 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002416 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002417 [lane] = 0;
2418 timings[reg_178]
2419 [channel][slot]
2420 [rank][lane].
2421 largest--;
2422 write_500(info, channel,
2423 timings
2424 [reg_178]
2425 [channel]
2426 [slot][rank]
2427 [lane].
2428 largest,
2429 get_timing_register_addr
2430 (lane, 0,
2431 slot, rank),
2432 9, 1);
2433 write_500(info, channel,
2434 timings
2435 [reg_178]
2436 [channel]
2437 [slot][rank]
2438 [lane].
2439 largest +
2440 info->
2441 training.
2442 lane_timings
2443 [1][channel]
2444 [slot][rank]
2445 [lane]
2446 -
2447 info->
2448 training.
2449 lane_timings
2450 [0][channel]
2451 [slot][rank]
2452 [lane],
2453 get_timing_register_addr
2454 (lane, 1,
2455 slot, rank),
2456 9, 1);
2457 }
2458 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002459 num_successfully_checked[lane]
2460 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002461 }
2462 }
2463 }
Felix Held04be2dd2018-07-29 04:53:22 +02002464 while (!check_bounded(num_successfully_checked, 3))
2465 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002466
2467 for (lane = 0; lane < 8; lane++) {
2468 write_500(info, channel,
2469 info->training.
2470 lane_timings[0][channel][slot][rank][lane],
2471 get_timing_register_addr(lane, 0, slot, rank),
2472 9, 1);
2473 write_500(info, channel,
2474 info->training.
2475 lane_timings[1][channel][slot][rank][lane],
2476 get_timing_register_addr(lane, 1, slot, rank),
2477 9, 1);
2478 if (timings[reg_178][channel][slot][rank][lane].
2479 largest <=
2480 timings[reg_178][channel][slot][rank][lane].
2481 smallest) {
2482 timings[reg_178][channel][slot][rank][lane].
2483 largest = 0;
2484 timings[reg_178][channel][slot][rank][lane].
2485 smallest = 0;
2486 }
2487 }
2488 }
2489}
2490
2491static void set_10b(struct raminfo *info, u8 val)
2492{
2493 int channel;
2494 int slot, rank;
2495 int lane;
2496
2497 if (read_1d0(0x10b, 6) == val)
2498 return;
2499
2500 write_1d0(val, 0x10b, 6, 1);
2501
2502 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2503 u16 reg_500;
2504 reg_500 = read_500(info, channel,
2505 get_timing_register_addr(lane, 0, slot,
2506 rank), 9);
2507 if (val == 1) {
2508 if (lut16[info->clock_speed_index] <= reg_500)
2509 reg_500 -= lut16[info->clock_speed_index];
2510 else
2511 reg_500 = 0;
2512 } else {
2513 reg_500 += lut16[info->clock_speed_index];
2514 }
2515 write_500(info, channel, reg_500,
2516 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2517 }
2518}
2519
2520static void set_ecc(int onoff)
2521{
2522 int channel;
2523 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2524 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002525 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002526 if (onoff)
2527 t |= 1;
2528 else
2529 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002530 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002531 }
2532}
2533
2534static void set_178(u8 val)
2535{
2536 if (val >= 31)
2537 val = val - 31;
2538 else
2539 val = 63 - val;
2540
2541 write_1d0(2 * val, 0x178, 7, 1);
2542}
2543
2544static void
2545write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2546 int type)
2547{
2548 int lane;
2549
2550 for (lane = 0; lane < 8; lane++)
2551 write_500(info, channel,
2552 info->training.
2553 lane_timings[type][channel][slot][rank][lane],
2554 get_timing_register_addr(lane, type, slot, rank), 9,
2555 0);
2556}
2557
2558static void
2559try_timing_offsets(struct raminfo *info, int channel,
2560 int slot, int rank, int totalrank)
2561{
2562 u16 count[8];
2563 enum state state[8];
2564 u8 lower_usable[8], upper_usable[8];
2565 int lane;
2566 int i;
2567 int flip = 1;
2568 int timing_offset;
2569
2570 for (i = 0; i < 8; i++)
2571 state[i] = BEFORE_USABLE;
2572
2573 memset(count, 0, sizeof(count));
2574
2575 for (lane = 0; lane < 8; lane++)
2576 write_500(info, channel,
2577 info->training.
2578 lane_timings[2][channel][slot][rank][lane] + 32,
2579 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2580
2581 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2582 timing_offset++) {
2583 u8 failmask;
2584 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2585 failmask = 0;
2586 for (i = 0; i < 2 && failmask != 0xff; i++) {
2587 flip = !flip;
2588 write_testing(info, totalrank, flip);
2589 failmask |= check_testing(info, totalrank, flip);
2590 }
2591 do_fsm(state, count, failmask, 10, 63, lower_usable,
2592 upper_usable, timing_offset);
2593 }
2594 write_1d0(0, 0x1bb, 6, 1);
2595 dump_timings(info);
2596 if (!validate_state(state))
2597 die("Couldn't discover DRAM timings (1)\n");
2598
2599 for (lane = 0; lane < 8; lane++) {
2600 u8 bias = 0;
2601
2602 if (info->silicon_revision) {
2603 int usable_length;
2604
2605 usable_length = upper_usable[lane] - lower_usable[lane];
2606 if (usable_length >= 20) {
2607 bias = usable_length / 2 - 10;
2608 if (bias >= 2)
2609 bias = 2;
2610 }
2611 }
2612 write_500(info, channel,
2613 info->training.
2614 lane_timings[2][channel][slot][rank][lane] +
2615 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2616 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2617 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2618 info->training.lane_timings[2][channel][slot][rank][lane] +
2619 lower_usable[lane];
2620 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2621 info->training.lane_timings[2][channel][slot][rank][lane] +
2622 upper_usable[lane];
2623 info->training.timing2_offset[channel][slot][rank][lane] =
2624 info->training.lane_timings[2][channel][slot][rank][lane];
2625 }
2626}
2627
2628static u8
2629choose_training(struct raminfo *info, int channel, int slot, int rank,
2630 int lane, timing_bounds_t * timings, u8 center_178)
2631{
2632 u16 central_weight;
2633 u16 side_weight;
2634 unsigned int sum = 0, count = 0;
2635 u8 span;
2636 u8 lower_margin, upper_margin;
2637 u8 reg_178;
2638 u8 result;
2639
2640 span = 12;
2641 central_weight = 20;
2642 side_weight = 20;
2643 if (info->silicon_revision == 1 && channel == 1) {
2644 central_weight = 5;
2645 side_weight = 20;
2646 if ((info->
2647 populated_ranks_mask[1] ^ (info->
2648 populated_ranks_mask[1] >> 2)) &
2649 1)
2650 span = 18;
2651 }
2652 if ((info->populated_ranks_mask[0] & 5) == 5) {
2653 central_weight = 20;
2654 side_weight = 20;
2655 }
2656 if (info->clock_speed_index >= 2
2657 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2658 if (info->silicon_revision == 1) {
2659 switch (channel) {
2660 case 0:
2661 if (lane == 1) {
2662 central_weight = 10;
2663 side_weight = 20;
2664 }
2665 break;
2666 case 1:
2667 if (lane == 6) {
2668 side_weight = 5;
2669 central_weight = 20;
2670 }
2671 break;
2672 }
2673 }
2674 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2675 side_weight = 5;
2676 central_weight = 20;
2677 }
2678 }
2679 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2680 reg_178 += span) {
2681 u8 smallest;
2682 u8 largest;
2683 largest = timings[reg_178][channel][slot][rank][lane].largest;
2684 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2685 if (largest - smallest + 1 >= 5) {
2686 unsigned int weight;
2687 if (reg_178 == center_178)
2688 weight = central_weight;
2689 else
2690 weight = side_weight;
2691 sum += weight * (largest + smallest);
2692 count += weight;
2693 }
2694 }
2695 dump_timings(info);
2696 if (count == 0)
2697 die("Couldn't discover DRAM timings (2)\n");
2698 result = sum / (2 * count);
2699 lower_margin =
2700 result - timings[center_178][channel][slot][rank][lane].smallest;
2701 upper_margin =
2702 timings[center_178][channel][slot][rank][lane].largest - result;
2703 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002704 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002705 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002706 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002707 return result;
2708}
2709
2710#define STANDARD_MIN_MARGIN 5
2711
2712static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2713{
2714 u16 margin[64];
2715 int lane, rank, slot, channel;
2716 u8 reg178;
2717 int count = 0, sum = 0;
2718
2719 for (reg178 = reg178_min[info->clock_speed_index];
2720 reg178 < reg178_max[info->clock_speed_index];
2721 reg178 += reg178_step[info->clock_speed_index]) {
2722 margin[reg178] = -1;
2723 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2724 int curmargin =
2725 timings[reg178][channel][slot][rank][lane].largest -
2726 timings[reg178][channel][slot][rank][lane].
2727 smallest + 1;
2728 if (curmargin < margin[reg178])
2729 margin[reg178] = curmargin;
2730 }
2731 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2732 u16 weight;
2733 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2734 sum += weight * reg178;
2735 count += weight;
2736 }
2737 }
2738 dump_timings(info);
2739 if (count == 0)
2740 die("Couldn't discover DRAM timings (3)\n");
2741
2742 u8 threshold;
2743
2744 for (threshold = 30; threshold >= 5; threshold--) {
2745 int usable_length = 0;
2746 int smallest_fount = 0;
2747 for (reg178 = reg178_min[info->clock_speed_index];
2748 reg178 < reg178_max[info->clock_speed_index];
2749 reg178 += reg178_step[info->clock_speed_index])
2750 if (margin[reg178] >= threshold) {
2751 usable_length +=
2752 reg178_step[info->clock_speed_index];
2753 info->training.reg178_largest =
2754 reg178 -
2755 2 * reg178_step[info->clock_speed_index];
2756
2757 if (!smallest_fount) {
2758 smallest_fount = 1;
2759 info->training.reg178_smallest =
2760 reg178 +
2761 reg178_step[info->
2762 clock_speed_index];
2763 }
2764 }
2765 if (usable_length >= 0x21)
2766 break;
2767 }
2768
2769 return sum / count;
2770}
2771
2772static int check_cached_sanity(struct raminfo *info)
2773{
2774 int lane;
2775 int slot, rank;
2776 int channel;
2777
2778 if (!info->cached_training)
2779 return 0;
2780
2781 for (channel = 0; channel < NUM_CHANNELS; channel++)
2782 for (slot = 0; slot < NUM_SLOTS; slot++)
2783 for (rank = 0; rank < NUM_RANKS; rank++)
2784 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2785 u16 cached_value, estimation_value;
2786 cached_value =
2787 info->cached_training->
2788 lane_timings[1][channel][slot][rank]
2789 [lane];
2790 if (cached_value >= 0x18
2791 && cached_value <= 0x1E7) {
2792 estimation_value =
2793 info->training.
2794 lane_timings[1][channel]
2795 [slot][rank][lane];
2796 if (estimation_value <
2797 cached_value - 24)
2798 return 0;
2799 if (estimation_value >
2800 cached_value + 24)
2801 return 0;
2802 }
2803 }
2804 return 1;
2805}
2806
2807static int try_cached_training(struct raminfo *info)
2808{
2809 u8 saved_243[2];
2810 u8 tm;
2811
2812 int channel, slot, rank, lane;
2813 int flip = 1;
2814 int i, j;
2815
2816 if (!check_cached_sanity(info))
2817 return 0;
2818
2819 info->training.reg178_center = info->cached_training->reg178_center;
2820 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2821 info->training.reg178_largest = info->cached_training->reg178_largest;
2822 memcpy(&info->training.timing_bounds,
2823 &info->cached_training->timing_bounds,
2824 sizeof(info->training.timing_bounds));
2825 memcpy(&info->training.timing_offset,
2826 &info->cached_training->timing_offset,
2827 sizeof(info->training.timing_offset));
2828
2829 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002830 saved_243[0] = MCHBAR8(0x243);
2831 saved_243[1] = MCHBAR8(0x643);
2832 MCHBAR8(0x243) = saved_243[0] | 2;
2833 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002834 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002835 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002836 if (read_1d0(0x10b, 6) & 1)
2837 set_10b(info, 0);
2838 for (tm = 0; tm < 2; tm++) {
2839 int totalrank;
2840
2841 set_178(tm ? info->cached_training->reg178_largest : info->
2842 cached_training->reg178_smallest);
2843
2844 totalrank = 0;
2845 /* Check timing ranges. With i == 0 we check smallest one and with
2846 i == 1 the largest bound. With j == 0 we check that on the bound
2847 it still works whereas with j == 1 we check that just outside of
2848 bound we fail.
2849 */
2850 FOR_POPULATED_RANKS_BACKWARDS {
2851 for (i = 0; i < 2; i++) {
2852 for (lane = 0; lane < 8; lane++) {
2853 write_500(info, channel,
2854 info->cached_training->
2855 timing2_bounds[channel][slot]
2856 [rank][lane][i],
2857 get_timing_register_addr(lane,
2858 3,
2859 slot,
2860 rank),
2861 9, 1);
2862
2863 if (!i)
2864 write_500(info, channel,
2865 info->
2866 cached_training->
2867 timing2_offset
2868 [channel][slot][rank]
2869 [lane],
2870 get_timing_register_addr
2871 (lane, 2, slot, rank),
2872 9, 1);
2873 write_500(info, channel,
2874 i ? info->cached_training->
2875 timing_bounds[tm][channel]
2876 [slot][rank][lane].
2877 largest : info->
2878 cached_training->
2879 timing_bounds[tm][channel]
2880 [slot][rank][lane].smallest,
2881 get_timing_register_addr(lane,
2882 0,
2883 slot,
2884 rank),
2885 9, 1);
2886 write_500(info, channel,
2887 info->cached_training->
2888 timing_offset[channel][slot]
2889 [rank][lane] +
2890 (i ? info->cached_training->
2891 timing_bounds[tm][channel]
2892 [slot][rank][lane].
2893 largest : info->
2894 cached_training->
2895 timing_bounds[tm][channel]
2896 [slot][rank][lane].
2897 smallest) - 64,
2898 get_timing_register_addr(lane,
2899 1,
2900 slot,
2901 rank),
2902 9, 1);
2903 }
2904 for (j = 0; j < 2; j++) {
2905 u8 failmask;
2906 u8 expected_failmask;
2907 char reg1b3;
2908
2909 reg1b3 = (j == 1) + 4;
2910 reg1b3 =
2911 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2912 write_1d0(reg1b3, 0x1bb, 6, 1);
2913 write_1d0(reg1b3, 0x1b3, 6, 1);
2914 write_1d0(reg1b3, 0x1a3, 6, 1);
2915
2916 flip = !flip;
2917 write_testing(info, totalrank, flip);
2918 failmask =
2919 check_testing(info, totalrank,
2920 flip);
2921 expected_failmask =
2922 j == 0 ? 0x00 : 0xff;
2923 if (failmask != expected_failmask)
2924 goto fail;
2925 }
2926 }
2927 totalrank++;
2928 }
2929 }
2930
2931 set_178(info->cached_training->reg178_center);
2932 if (info->use_ecc)
2933 set_ecc(1);
2934 write_training_data(info);
2935 write_1d0(0, 322, 3, 1);
2936 info->training = *info->cached_training;
2937
2938 write_1d0(0, 0x1bb, 6, 1);
2939 write_1d0(0, 0x1b3, 6, 1);
2940 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002941 MCHBAR8(0x243) = saved_243[0];
2942 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002943
2944 return 1;
2945
2946fail:
2947 FOR_POPULATED_RANKS {
2948 write_500_timings_type(info, channel, slot, rank, 1);
2949 write_500_timings_type(info, channel, slot, rank, 2);
2950 write_500_timings_type(info, channel, slot, rank, 3);
2951 }
2952
2953 write_1d0(0, 0x1bb, 6, 1);
2954 write_1d0(0, 0x1b3, 6, 1);
2955 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002956 MCHBAR8(0x243) = saved_243[0];
2957 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002958
2959 return 0;
2960}
2961
2962static void do_ram_training(struct raminfo *info)
2963{
2964 u8 saved_243[2];
2965 int totalrank = 0;
2966 u8 reg_178;
2967 int niter;
2968
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002969 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002970 int lane, rank, slot, channel;
2971 u8 reg178_center;
2972
2973 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002974 saved_243[0] = MCHBAR8(0x243);
2975 saved_243[1] = MCHBAR8(0x643);
2976 MCHBAR8(0x243) = saved_243[0] | 2;
2977 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002978 switch (info->clock_speed_index) {
2979 case 0:
2980 niter = 5;
2981 break;
2982 case 1:
2983 niter = 10;
2984 break;
2985 default:
2986 niter = 19;
2987 break;
2988 }
2989 set_ecc(0);
2990
2991 FOR_POPULATED_RANKS_BACKWARDS {
2992 int i;
2993
2994 write_500_timings_type(info, channel, slot, rank, 0);
2995
2996 write_testing(info, totalrank, 0);
2997 for (i = 0; i < niter; i++) {
2998 write_testing_type2(info, totalrank, 2, i, 0);
2999 write_testing_type2(info, totalrank, 3, i, 1);
3000 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003001 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003002 totalrank++;
3003 }
3004
3005 if (reg178_min[info->clock_speed_index] <
3006 reg178_max[info->clock_speed_index])
3007 memset(timings[reg178_min[info->clock_speed_index]], 0,
3008 sizeof(timings[0]) *
3009 (reg178_max[info->clock_speed_index] -
3010 reg178_min[info->clock_speed_index]));
3011 for (reg_178 = reg178_min[info->clock_speed_index];
3012 reg_178 < reg178_max[info->clock_speed_index];
3013 reg_178 += reg178_step[info->clock_speed_index]) {
3014 totalrank = 0;
3015 set_178(reg_178);
3016 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3017 for (slot = 0; slot < NUM_SLOTS; slot++)
3018 for (rank = 0; rank < NUM_RANKS; rank++) {
3019 memset(&timings[reg_178][channel][slot]
3020 [rank][0].smallest, 0, 16);
3021 if (info->
3022 populated_ranks[channel][slot]
3023 [rank]) {
3024 train_ram_at_178(info, channel,
3025 slot, rank,
3026 totalrank,
3027 reg_178, 1,
3028 niter,
3029 timings);
3030 totalrank++;
3031 }
3032 }
3033 }
3034
3035 reg178_center = choose_reg178(info, timings);
3036
3037 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3038 info->training.timing_bounds[0][channel][slot][rank][lane].
3039 smallest =
3040 timings[info->training.
3041 reg178_smallest][channel][slot][rank][lane].
3042 smallest;
3043 info->training.timing_bounds[0][channel][slot][rank][lane].
3044 largest =
3045 timings[info->training.
3046 reg178_smallest][channel][slot][rank][lane].largest;
3047 info->training.timing_bounds[1][channel][slot][rank][lane].
3048 smallest =
3049 timings[info->training.
3050 reg178_largest][channel][slot][rank][lane].smallest;
3051 info->training.timing_bounds[1][channel][slot][rank][lane].
3052 largest =
3053 timings[info->training.
3054 reg178_largest][channel][slot][rank][lane].largest;
3055 info->training.timing_offset[channel][slot][rank][lane] =
3056 info->training.lane_timings[1][channel][slot][rank][lane]
3057 -
3058 info->training.lane_timings[0][channel][slot][rank][lane] +
3059 64;
3060 }
3061
3062 if (info->silicon_revision == 1
3063 && (info->
3064 populated_ranks_mask[1] ^ (info->
3065 populated_ranks_mask[1] >> 2)) & 1) {
3066 int ranks_after_channel1;
3067
3068 totalrank = 0;
3069 for (reg_178 = reg178_center - 18;
3070 reg_178 <= reg178_center + 18; reg_178 += 18) {
3071 totalrank = 0;
3072 set_178(reg_178);
3073 for (slot = 0; slot < NUM_SLOTS; slot++)
3074 for (rank = 0; rank < NUM_RANKS; rank++) {
3075 if (info->
3076 populated_ranks[1][slot][rank]) {
3077 train_ram_at_178(info, 1, slot,
3078 rank,
3079 totalrank,
3080 reg_178, 0,
3081 niter,
3082 timings);
3083 totalrank++;
3084 }
3085 }
3086 }
3087 ranks_after_channel1 = totalrank;
3088
3089 for (reg_178 = reg178_center - 12;
3090 reg_178 <= reg178_center + 12; reg_178 += 12) {
3091 totalrank = ranks_after_channel1;
3092 set_178(reg_178);
3093 for (slot = 0; slot < NUM_SLOTS; slot++)
3094 for (rank = 0; rank < NUM_RANKS; rank++)
3095 if (info->
3096 populated_ranks[0][slot][rank]) {
3097 train_ram_at_178(info, 0, slot,
3098 rank,
3099 totalrank,
3100 reg_178, 0,
3101 niter,
3102 timings);
3103 totalrank++;
3104 }
3105
3106 }
3107 } else {
3108 for (reg_178 = reg178_center - 12;
3109 reg_178 <= reg178_center + 12; reg_178 += 12) {
3110 totalrank = 0;
3111 set_178(reg_178);
3112 FOR_POPULATED_RANKS_BACKWARDS {
3113 train_ram_at_178(info, channel, slot, rank,
3114 totalrank, reg_178, 0, niter,
3115 timings);
3116 totalrank++;
3117 }
3118 }
3119 }
3120
3121 set_178(reg178_center);
3122 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3123 u16 tm0;
3124
3125 tm0 =
3126 choose_training(info, channel, slot, rank, lane, timings,
3127 reg178_center);
3128 write_500(info, channel, tm0,
3129 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3130 write_500(info, channel,
3131 tm0 +
3132 info->training.
3133 lane_timings[1][channel][slot][rank][lane] -
3134 info->training.
3135 lane_timings[0][channel][slot][rank][lane],
3136 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3137 }
3138
3139 totalrank = 0;
3140 FOR_POPULATED_RANKS_BACKWARDS {
3141 try_timing_offsets(info, channel, slot, rank, totalrank);
3142 totalrank++;
3143 }
Felix Held04be2dd2018-07-29 04:53:22 +02003144 MCHBAR8(0x243) = saved_243[0];
3145 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003146 write_1d0(0, 0x142, 3, 1);
3147 info->training.reg178_center = reg178_center;
3148}
3149
3150static void ram_training(struct raminfo *info)
3151{
3152 u16 saved_fc4;
3153
Felix Held04be2dd2018-07-29 04:53:22 +02003154 saved_fc4 = MCHBAR16(0xfc4);
3155 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003156
3157 if (info->revision >= 8)
3158 read_4090(info);
3159
3160 if (!try_cached_training(info))
3161 do_ram_training(info);
3162 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3163 && info->clock_speed_index < 2)
3164 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003165 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003166}
3167
Martin Roth468d02c2019-10-23 21:44:42 -06003168static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003169{
Martin Roth468d02c2019-10-23 21:44:42 -06003170 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003171 if (a > b) {
3172 t = a;
3173 a = b;
3174 b = t;
3175 }
3176 /* invariant a < b. */
3177 while (a) {
3178 t = b % a;
3179 b = a;
3180 a = t;
3181 }
3182 return b;
3183}
3184
3185static inline int div_roundup(int a, int b)
3186{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003187 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003188}
3189
Martin Roth468d02c2019-10-23 21:44:42 -06003190static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003191{
3192 return (a * b) / gcd(a, b);
3193}
3194
3195struct stru1 {
3196 u8 freqs_reversed;
3197 u8 freq_diff_reduced;
3198 u8 freq_min_reduced;
3199 u8 divisor_f4_to_fmax;
3200 u8 divisor_f3_to_fmax;
3201 u8 freq4_to_max_remainder;
3202 u8 freq3_to_2_remainder;
3203 u8 freq3_to_2_remaindera;
3204 u8 freq4_to_2_remainder;
3205 int divisor_f3_to_f1, divisor_f4_to_f2;
3206 int common_time_unit_ps;
3207 int freq_max_reduced;
3208};
3209
3210static void
3211compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3212 int num_cycles_2, int num_cycles_1, int round_it,
3213 int add_freqs, struct stru1 *result)
3214{
3215 int g;
3216 int common_time_unit_ps;
3217 int freq1_reduced, freq2_reduced;
3218 int freq_min_reduced;
3219 int freq_max_reduced;
3220 int freq3, freq4;
3221
3222 g = gcd(freq1, freq2);
3223 freq1_reduced = freq1 / g;
3224 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003225 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3226 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003227
3228 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3229 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3230 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3231 if (add_freqs) {
3232 freq3 += freq2_reduced;
3233 freq4 += freq1_reduced;
3234 }
3235
3236 if (round_it) {
3237 result->freq3_to_2_remainder = 0;
3238 result->freq3_to_2_remaindera = 0;
3239 result->freq4_to_max_remainder = 0;
3240 result->divisor_f4_to_f2 = 0;
3241 result->divisor_f3_to_f1 = 0;
3242 } else {
3243 if (freq2_reduced < freq1_reduced) {
3244 result->freq3_to_2_remainder =
3245 result->freq3_to_2_remaindera =
3246 freq3 % freq1_reduced - freq1_reduced + 1;
3247 result->freq4_to_max_remainder =
3248 -(freq4 % freq1_reduced);
3249 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3250 result->divisor_f4_to_f2 =
3251 (freq4 -
3252 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3253 result->freq4_to_2_remainder =
3254 -(char)((freq1_reduced - freq2_reduced) +
3255 ((u8) freq4 -
3256 (freq1_reduced -
3257 freq2_reduced)) % (u8) freq2_reduced);
3258 } else {
3259 if (freq2_reduced > freq1_reduced) {
3260 result->freq4_to_max_remainder =
3261 (freq4 % freq2_reduced) - freq2_reduced + 1;
3262 result->freq4_to_2_remainder =
3263 freq4 % freq_max_reduced -
3264 freq_max_reduced + 1;
3265 } else {
3266 result->freq4_to_max_remainder =
3267 -(freq4 % freq2_reduced);
3268 result->freq4_to_2_remainder =
3269 -(char)(freq4 % freq_max_reduced);
3270 }
3271 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3272 result->divisor_f3_to_f1 =
3273 (freq3 -
3274 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3275 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3276 result->freq3_to_2_remaindera =
3277 -(char)((freq_max_reduced - freq_min_reduced) +
3278 (freq3 -
3279 (freq_max_reduced -
3280 freq_min_reduced)) % freq1_reduced);
3281 }
3282 }
3283 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3284 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3285 if (round_it) {
3286 if (freq2_reduced > freq1_reduced) {
3287 if (freq3 % freq_max_reduced)
3288 result->divisor_f3_to_fmax++;
3289 }
3290 if (freq2_reduced < freq1_reduced) {
3291 if (freq4 % freq_max_reduced)
3292 result->divisor_f4_to_fmax++;
3293 }
3294 }
3295 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3296 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3297 result->freq_min_reduced = freq_min_reduced;
3298 result->common_time_unit_ps = common_time_unit_ps;
3299 result->freq_max_reduced = freq_max_reduced;
3300}
3301
3302static void
3303set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3304 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3305 int num_cycles_4, int reverse)
3306{
3307 struct stru1 vv;
3308 char multiplier;
3309
3310 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3311 0, 1, &vv);
3312
3313 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003314 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003315 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3316 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3317 div_roundup(num_cycles_1,
3318 vv.common_time_unit_ps) +
3319 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3320 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3321
3322 u32 y =
3323 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3324 vv.freq_max_reduced * multiplier)
3325 | (vv.
3326 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3327 multiplier) << 16) | ((u8) (vv.
3328 freq_min_reduced
3329 *
3330 multiplier)
3331 << 24);
3332 u32 x =
3333 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3334 divisor_f3_to_f1
3335 << 16)
3336 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3337 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003338 MCHBAR32(reg) = y;
3339 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003340 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003341 MCHBAR32(reg + 4) = y;
3342 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003343 }
3344}
3345
3346static void
3347set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3348 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3349 int num_cycles_4)
3350{
3351 struct stru1 ratios1;
3352 struct stru1 ratios2;
3353
3354 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3355 0, 1, &ratios2);
3356 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3357 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003358 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003359 ratios1.freq4_to_max_remainder | (ratios2.
3360 freq4_to_max_remainder
3361 << 8)
3362 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3363 divisor_f4_to_fmax
3364 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003365 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3366 (ratios2.freq4_to_max_remainder << 8) |
3367 (ratios1.divisor_f4_to_fmax << 16) |
3368 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003369}
3370
3371static void
3372set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3373 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3374{
3375 struct stru1 ratios;
3376
3377 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3378 round_it, add_freqs, &ratios);
3379 switch (mode) {
3380 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003381 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3382 (ratios.freqs_reversed << 8);
3383 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3384 (ratios.freq4_to_max_remainder << 8) |
3385 (ratios.divisor_f3_to_fmax << 16) |
3386 (ratios.divisor_f4_to_fmax << 20) |
3387 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003388 break;
3389
3390 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003391 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3392 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003393 break;
3394
3395 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003396 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3397 (ratios.freq4_to_max_remainder << 8) |
3398 (ratios.divisor_f3_to_fmax << 16) |
3399 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003400 break;
3401
3402 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003403 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3404 (ratios.divisor_f4_to_fmax << 8) |
3405 (ratios.freqs_reversed << 12) |
3406 (ratios.freq_min_reduced << 16) |
3407 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003408 break;
3409 }
3410}
3411
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003412static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003413{
3414 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3415 0, 1);
3416 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3417 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3418 1);
3419 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3420 frequency_11(info), 1231, 1524, 0, 1);
3421 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3422 frequency_11(info) / 2, 1278, 2008, 0, 1);
3423 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3424 1167, 1539, 0, 1);
3425 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3426 frequency_11(info) / 2, 1403, 1318, 0, 1);
3427 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3428 1);
3429 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3430 1);
3431 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3432 1, 1);
3433 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3434 1);
3435 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3436 frequency_11(info) / 2, 4000, 0, 0, 0);
3437 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3438 frequency_11(info) / 2, 4000, 4000, 0, 0);
3439
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003440 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003441 printk(RAM_SPEW, "[6dc] <= %x\n",
3442 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003443 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003444 } else
3445 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3446 info->delay46_ps[0], 0,
3447 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3449 frequency_11(info), 2500, 0, 0, 0);
3450 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3451 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003452 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003453 printk(RAM_SPEW, "[6e8] <= %x\n",
3454 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003455 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003456 } else
3457 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3458 info->delay46_ps[1], 0,
3459 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003460 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3461 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3462 470, 0);
3463 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3464 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3465 454, 459, 0);
3466 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3467 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3468 2588, 0);
3469 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3470 2405, 0);
3471 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3472 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3473 480, 0);
3474 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003475 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3476 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477}
3478
3479static u16 get_max_timing(struct raminfo *info, int channel)
3480{
3481 int slot, rank, lane;
3482 u16 ret = 0;
3483
Felix Held04be2dd2018-07-29 04:53:22 +02003484 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003485 return 384;
3486
3487 if (info->revision < 8)
3488 return 256;
3489
3490 for (slot = 0; slot < NUM_SLOTS; slot++)
3491 for (rank = 0; rank < NUM_RANKS; rank++)
3492 if (info->populated_ranks[channel][slot][rank])
3493 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003494 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003495 get_timing_register_addr
3496 (lane, 0, slot,
3497 rank), 9));
3498 return ret;
3499}
3500
3501static void set_274265(struct raminfo *info)
3502{
3503 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3504 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3505 int delay_e_over_cycle_ps;
3506 int cycletime_ps;
3507 int channel;
3508
3509 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003510 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003511 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3512 cycletime_ps =
3513 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3514 delay_d_ps =
3515 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3516 - info->some_delay_3_ps_rounded + 200;
3517 if (!
3518 ((info->silicon_revision == 0
3519 || info->silicon_revision == 1)
3520 && (info->revision >= 8)))
3521 delay_d_ps += halfcycle_ps(info) * 2;
3522 delay_d_ps +=
3523 halfcycle_ps(info) * (!info->revision_flag_1 +
3524 info->some_delay_2_halfcycles_ceil +
3525 2 * info->some_delay_1_cycle_floor +
3526 info->clock_speed_index +
3527 2 * info->cas_latency - 7 + 11);
3528 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3529
Felix Held04be2dd2018-07-29 04:53:22 +02003530 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3531 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3532 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003533 delay_d_ps += 650;
3534 delay_c_ps = delay_d_ps + 1800;
3535 if (delay_c_ps <= delay_a_ps)
3536 delay_e_ps = 0;
3537 else
3538 delay_e_ps =
3539 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3540 cycletime_ps);
3541
3542 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3543 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3544 delay_f_cycles =
3545 div_roundup(2500 - delay_e_over_cycle_ps,
3546 2 * halfcycle_ps(info));
3547 if (delay_f_cycles > delay_e_cycles) {
3548 info->delay46_ps[channel] = delay_e_ps;
3549 delay_e_cycles = 0;
3550 } else {
3551 info->delay46_ps[channel] =
3552 delay_e_over_cycle_ps +
3553 2 * halfcycle_ps(info) * delay_f_cycles;
3554 delay_e_cycles -= delay_f_cycles;
3555 }
3556
3557 if (info->delay46_ps[channel] < 2500) {
3558 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003559 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003560 }
3561 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3562 if (delay_b_ps <= delay_a_ps)
3563 delay_b_ps = 0;
3564 else
3565 delay_b_ps -= delay_a_ps;
3566 info->delay54_ps[channel] =
3567 cycletime_ps * div_roundup(delay_b_ps,
3568 cycletime_ps) -
3569 2 * halfcycle_ps(info) * delay_e_cycles;
3570 if (info->delay54_ps[channel] < 2500)
3571 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003572 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003573 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3574 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003575 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003576 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003577 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003578 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3579 4 * halfcycle_ps(info)) - 6;
3580 MCHBAR32((channel << 10) + 0x274) =
3581 info->training.reg274265[channel][1] |
3582 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003583 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003584 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3585 4 * halfcycle_ps(info)) + 1;
3586 MCHBAR16((channel << 10) + 0x265) =
3587 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003588 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003589 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003590 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003591 else
Felix Held04be2dd2018-07-29 04:53:22 +02003592 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003593}
3594
3595static void restore_274265(struct raminfo *info)
3596{
3597 int channel;
3598
3599 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003600 MCHBAR32((channel << 10) + 0x274) =
3601 (info->cached_training->reg274265[channel][0] << 16) |
3602 info->cached_training->reg274265[channel][1];
3603 MCHBAR16((channel << 10) + 0x265) =
3604 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003606 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003607 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608 else
Felix Held04be2dd2018-07-29 04:53:22 +02003609 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610}
3611
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612static void dmi_setup(void)
3613{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003614 gav(DMIBAR8(0x254));
3615 DMIBAR8(0x254) = 0x1;
3616 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003617 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618
Angel Ponsd071c4d2020-09-14 23:51:35 +02003619 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620
3621 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3622 DEFAULT_GPIOBASE | 0x38);
3623 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3624}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003626void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003629 u16 ggc;
3630 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631
Felix Held04be2dd2018-07-29 04:53:22 +02003632 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003633 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3634 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003635 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003636 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
3639 dmi_setup();
3640
Felix Held04be2dd2018-07-29 04:53:22 +02003641 MCHBAR16(0x1170) = 0xa880;
3642 MCHBAR8(0x11c1) = 0x1;
3643 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003644 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003646 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3647 /* 0 for 32MB */
3648 gfxsize = 0;
3649 }
3650
3651 ggc = 0xb00 | ((gfxsize + 5) << 4);
3652
Angel Pons16fe1e02020-07-22 16:12:33 +02003653 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654
3655 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003656 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
3658 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003659 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003660 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003661 MCHBAR16_OR(0x2c30, 0x200);
3662 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003663 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003664 pci_read_config8(GMA, MSAC); // = 0x2
3665 pci_write_config8(GMA, MSAC, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003666 read8(DEFAULT_RCBA + 0x2318);
3667 write8(DEFAULT_RCBA + 0x2318, 0x47);
3668 read8(DEFAULT_RCBA + 0x2320);
3669 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670 }
3671
Felix Heldf83d80b2018-07-29 05:30:30 +02003672 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673
Angel Pons16fe1e02020-07-22 16:12:33 +02003674 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003675 gav(read32(DEFAULT_RCBA + 0x3428));
3676 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003677}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003678
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003679void raminit(const int s3resume, const u8 *spd_addrmap)
3680{
Martin Roth468d02c2019-10-23 21:44:42 -06003681 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003682 int i;
3683 struct raminfo info;
3684 u8 x2ca8;
3685 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003686 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003687
Felix Held04be2dd2018-07-29 04:53:22 +02003688 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003689
3690 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3691
Angel Pons16fe1e02020-07-22 16:12:33 +02003692 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003693
3694 memset(&info, 0x5a, sizeof(info));
3695
3696 info.last_500_command[0] = 0;
3697 info.last_500_command[1] = 0;
3698
3699 info.fsb_frequency = 135 * 2;
3700 info.board_lane_delay[0] = 0x14;
3701 info.board_lane_delay[1] = 0x07;
3702 info.board_lane_delay[2] = 0x07;
3703 info.board_lane_delay[3] = 0x08;
3704 info.board_lane_delay[4] = 0x56;
3705 info.board_lane_delay[5] = 0x04;
3706 info.board_lane_delay[6] = 0x04;
3707 info.board_lane_delay[7] = 0x05;
3708 info.board_lane_delay[8] = 0x10;
3709
3710 info.training.reg_178 = 0;
3711 info.training.reg_10b = 0;
3712
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713 info.memory_reserved_for_heci_mb = 0;
3714
3715 /* before SPD */
3716 timestamp_add_now(101);
3717
Felix Held29a9c072018-07-29 01:34:45 +02003718 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003719 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003720
3721 collect_system_info(&info);
3722
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3724
3725 info.use_ecc = 1;
3726 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003727 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728 int v;
3729 int try;
3730 int addr;
3731 const u8 useful_addresses[] = {
3732 DEVICE_TYPE,
3733 MODULE_TYPE,
3734 DENSITY,
3735 RANKS_AND_DQ,
3736 MEMORY_BUS_WIDTH,
3737 TIMEBASE_DIVIDEND,
3738 TIMEBASE_DIVISOR,
3739 CYCLETIME,
3740 CAS_LATENCIES_LSB,
3741 CAS_LATENCIES_MSB,
3742 CAS_LATENCY_TIME,
3743 0x11, 0x12, 0x13, 0x14, 0x15,
3744 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3745 0x1c, 0x1d,
3746 THERMAL_AND_REFRESH,
3747 0x20,
3748 REFERENCE_RAW_CARD_USED,
3749 RANK1_ADDRESS_MAPPING,
3750 0x75, 0x76, 0x77, 0x78,
3751 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3752 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3753 0x85, 0x86, 0x87, 0x88,
3754 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3755 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3756 0x95
3757 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003758 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003759 continue;
3760 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003761 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003762 DEVICE_TYPE);
3763 if (v >= 0)
3764 break;
3765 }
3766 if (v < 0)
3767 continue;
3768 for (addr = 0;
3769 addr <
3770 sizeof(useful_addresses) /
3771 sizeof(useful_addresses[0]); addr++)
3772 gav(info.
3773 spd[channel][0][useful_addresses
3774 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003775 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003776 useful_addresses
3777 [addr]));
3778 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3779 die("Only DDR3 is supported");
3780
3781 v = info.spd[channel][0][RANKS_AND_DQ];
3782 info.populated_ranks[channel][0][0] = 1;
3783 info.populated_ranks[channel][0][1] =
3784 ((v >> 3) & 7);
3785 if (((v >> 3) & 7) > 1)
3786 die("At most 2 ranks are supported");
3787 if ((v & 7) == 0 || (v & 7) > 2)
3788 die("Only x8 and x16 modules are supported");
3789 if ((info.
3790 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3791 && (info.
3792 spd[channel][slot][MODULE_TYPE] & 0xF)
3793 != 3)
3794 die("Registered memory is not supported");
3795 info.is_x16_module[channel][0] = (v & 7) - 1;
3796 info.density[channel][slot] =
3797 info.spd[channel][slot][DENSITY] & 0xF;
3798 if (!
3799 (info.
3800 spd[channel][slot][MEMORY_BUS_WIDTH] &
3801 0x18))
3802 info.use_ecc = 0;
3803 }
3804
3805 gav(0x55);
3806
3807 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3808 int v = 0;
3809 for (slot = 0; slot < NUM_SLOTS; slot++)
3810 for (rank = 0; rank < NUM_RANKS; rank++)
3811 v |= info.
3812 populated_ranks[channel][slot][rank]
3813 << (2 * slot + rank);
3814 info.populated_ranks_mask[channel] = v;
3815 }
3816
3817 gav(0x55);
3818
Angel Pons16fe1e02020-07-22 16:12:33 +02003819 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820 }
3821
3822 /* after SPD */
3823 timestamp_add_now(102);
3824
Felix Held04be2dd2018-07-29 04:53:22 +02003825 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003826
3827 collect_system_info(&info);
3828 calculate_timings(&info);
3829
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003830 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003831 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003832 if (x2ca8 == 0 && (reg8 & 0x80)) {
3833 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3834 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3835 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3836 */
3837
3838 /* Clear bit7. */
3839
3840 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3841 (reg8 & ~(1 << 7)));
3842
3843 printk(BIOS_INFO,
3844 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003845 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003846 }
3847 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003848
3849 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003850 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3851 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003852
3853 compute_derived_timings(&info);
3854
3855 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003856 gav(MCHBAR8(0x164));
3857 MCHBAR8(0x164) = 0x26;
3858 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859 }
3860
Felix Held04be2dd2018-07-29 04:53:22 +02003861 MCHBAR32_OR(0x18b4, 0x210000);
3862 MCHBAR32_OR(0x1890, 0x2000000);
3863 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003864
Angel Ponsa457e352020-07-22 18:17:33 +02003865 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3866 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867
Felix Held04be2dd2018-07-29 04:53:22 +02003868 gav(MCHBAR16(0x2c10));
3869 MCHBAR16(0x2c10) = 0x412;
3870 gav(MCHBAR16(0x2c10));
3871 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872
Felix Held04be2dd2018-07-29 04:53:22 +02003873 gav(MCHBAR8(0x2ca8)); // !!!!
3874 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875
Angel Ponsa457e352020-07-22 18:17:33 +02003876 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3877 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003878 gav(MCHBAR32(0x1c04)); // !!!!
3879 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880
3881 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003882 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003883 }
3884
Felix Held04be2dd2018-07-29 04:53:22 +02003885 MCHBAR32(0x18d8) = 0x120000;
3886 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003887 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3888 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003889 MCHBAR32(0x18d8) = 0x40000;
3890 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003891 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3892 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003893 MCHBAR32(0x18d8) = 0x180000;
3894 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3896 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003898
Felix Held04be2dd2018-07-29 04:53:22 +02003899 gav(MCHBAR32(0x18dc)); // !!!!
3900 MCHBAR32(0x18dc) = 0x3;
3901 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003902
3903 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003904 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905 }
3906
Felix Held04be2dd2018-07-29 04:53:22 +02003907 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003908 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003909 MCHBAR32(0x1a10) = 0x4200010e;
3910 MCHBAR32_OR(0x18b8, 0x200);
3911 gav(MCHBAR32(0x1918)); // !!!!
3912 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 gav(MCHBAR32(0x18b8)); // !!!!
3915 MCHBAR32(0x18b8) = 0xe00;
3916 gav(MCHBAR32(0x182c)); // !!!!
3917 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003918 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3919 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003920 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3921 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922
Felix Held04be2dd2018-07-29 04:53:22 +02003923 MCHBAR32_AND(0x18b4, 0xffff7fff);
3924 gav(MCHBAR32(0x1a68)); // !!!!
3925 MCHBAR32(0x1a68) = 0x343800;
3926 gav(MCHBAR32(0x1e68)); // !!!!
3927 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003928
3929 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003930 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003931 }
3932
Angel Pons08143572020-07-22 17:47:06 +02003933 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3934 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3935 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3936 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3937 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003938 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3939 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003940 gav(MCHBAR32(0x1af0)); // !!!!
3941 gav(MCHBAR32(0x1af0)); // !!!!
3942 MCHBAR32(0x1af0) = 0x1f020003;
3943 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003944
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003945 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003946 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003947 }
3948
Felix Held04be2dd2018-07-29 04:53:22 +02003949 gav(MCHBAR32(0x1890)); // !!!!
3950 MCHBAR32(0x1890) = 0x80102;
3951 gav(MCHBAR32(0x18b4)); // !!!!
3952 MCHBAR32(0x18b4) = 0x216000;
3953 MCHBAR32(0x18a4) = 0x22222222;
3954 MCHBAR32(0x18a8) = 0x22222222;
3955 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003956
3957 udelay(1000);
3958
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003959 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003960
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003961 if (x2ca8 == 0) {
3962 int j;
3963 if (s3resume && info.cached_training) {
3964 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003965 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003966 info.cached_training->reg2ca9_bit0);
3967 for (i = 0; i < 2; i++)
3968 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003969 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003970 i, j, info.cached_training->reg274265[i][j]);
3971 } else {
3972 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003973 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003974 info.training.reg2ca9_bit0);
3975 for (i = 0; i < 2; i++)
3976 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003977 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003978 i, j, info.training.reg274265[i][j]);
3979 }
3980
3981 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003982
3983 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003984 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003985 }
3986
3987 udelay(1000);
3988
3989 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003990 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003991 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003992 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3993 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3994 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003995
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003996 MCHBAR8(0x1150);
3997 MCHBAR8(0x1151);
3998 MCHBAR8(0x1022);
3999 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004000 MCHBAR32(0x1300) = 0x60606060;
4001 MCHBAR32(0x1304) = 0x60606060;
4002 MCHBAR32(0x1308) = 0x78797a7b;
4003 MCHBAR32(0x130c) = 0x7c7d7e7f;
4004 MCHBAR32(0x1310) = 0x60606060;
4005 MCHBAR32(0x1314) = 0x60606060;
4006 MCHBAR32(0x1318) = 0x60606060;
4007 MCHBAR32(0x131c) = 0x60606060;
4008 MCHBAR32(0x1320) = 0x50515253;
4009 MCHBAR32(0x1324) = 0x54555657;
4010 MCHBAR32(0x1328) = 0x58595a5b;
4011 MCHBAR32(0x132c) = 0x5c5d5e5f;
4012 MCHBAR32(0x1330) = 0x40414243;
4013 MCHBAR32(0x1334) = 0x44454647;
4014 MCHBAR32(0x1338) = 0x48494a4b;
4015 MCHBAR32(0x133c) = 0x4c4d4e4f;
4016 MCHBAR32(0x1340) = 0x30313233;
4017 MCHBAR32(0x1344) = 0x34353637;
4018 MCHBAR32(0x1348) = 0x38393a3b;
4019 MCHBAR32(0x134c) = 0x3c3d3e3f;
4020 MCHBAR32(0x1350) = 0x20212223;
4021 MCHBAR32(0x1354) = 0x24252627;
4022 MCHBAR32(0x1358) = 0x28292a2b;
4023 MCHBAR32(0x135c) = 0x2c2d2e2f;
4024 MCHBAR32(0x1360) = 0x10111213;
4025 MCHBAR32(0x1364) = 0x14151617;
4026 MCHBAR32(0x1368) = 0x18191a1b;
4027 MCHBAR32(0x136c) = 0x1c1d1e1f;
4028 MCHBAR32(0x1370) = 0x10203;
4029 MCHBAR32(0x1374) = 0x4050607;
4030 MCHBAR32(0x1378) = 0x8090a0b;
4031 MCHBAR32(0x137c) = 0xc0d0e0f;
4032 MCHBAR8(0x11cc) = 0x4e;
4033 MCHBAR32(0x1110) = 0x73970404;
4034 MCHBAR32(0x1114) = 0x72960404;
4035 MCHBAR32(0x1118) = 0x6f950404;
4036 MCHBAR32(0x111c) = 0x6d940404;
4037 MCHBAR32(0x1120) = 0x6a930404;
4038 MCHBAR32(0x1124) = 0x68a41404;
4039 MCHBAR32(0x1128) = 0x66a21404;
4040 MCHBAR32(0x112c) = 0x63a01404;
4041 MCHBAR32(0x1130) = 0x609e1404;
4042 MCHBAR32(0x1134) = 0x5f9c1404;
4043 MCHBAR32(0x1138) = 0x5c961404;
4044 MCHBAR32(0x113c) = 0x58a02404;
4045 MCHBAR32(0x1140) = 0x54942404;
4046 MCHBAR32(0x1190) = 0x900080a;
4047 MCHBAR16(0x11c0) = 0xc40b;
4048 MCHBAR16(0x11c2) = 0x303;
4049 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004050 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004051 MCHBAR32(0x11b8) = 0x70c3000;
4052 MCHBAR8(0x11ec) = 0xa;
4053 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004054 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004055 MCHBAR16(0x11ca) = 0xfa;
4056 MCHBAR32(0x11e4) = 0x4e20;
4057 MCHBAR8(0x11bc) = 0xf;
4058 MCHBAR16(0x11da) = 0x19;
4059 MCHBAR16(0x11ba) = 0x470c;
4060 MCHBAR32(0x1680) = 0xe6ffe4ff;
4061 MCHBAR32(0x1684) = 0xdeffdaff;
4062 MCHBAR32(0x1688) = 0xd4ffd0ff;
4063 MCHBAR32(0x168c) = 0xccffc6ff;
4064 MCHBAR32(0x1690) = 0xc0ffbeff;
4065 MCHBAR32(0x1694) = 0xb8ffb0ff;
4066 MCHBAR32(0x1698) = 0xa8ff0000;
4067 MCHBAR32(0x169c) = 0xc00;
4068 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004069 }
4070
Felix Held04be2dd2018-07-29 04:53:22 +02004071 MCHBAR32(0x124c) = 0x15040d00;
4072 MCHBAR32(0x1250) = 0x7f0000;
4073 MCHBAR32(0x1254) = 0x1e220004;
4074 MCHBAR32(0x1258) = 0x4000004;
4075 MCHBAR32(0x1278) = 0x0;
4076 MCHBAR32(0x125c) = 0x0;
4077 MCHBAR32(0x1260) = 0x0;
4078 MCHBAR32(0x1264) = 0x0;
4079 MCHBAR32(0x1268) = 0x0;
4080 MCHBAR32(0x126c) = 0x0;
4081 MCHBAR32(0x1270) = 0x0;
4082 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004083 }
4084
4085 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004086 MCHBAR16(0x1214) = 0x320;
4087 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004088 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4089 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004090 MCHBAR32(0x1400) = 0x13040020;
4091 MCHBAR32(0x1404) = 0xe090120;
4092 MCHBAR32(0x1408) = 0x5120220;
4093 MCHBAR32(0x140c) = 0x5120330;
4094 MCHBAR32(0x1410) = 0xe090220;
4095 MCHBAR32(0x1414) = 0x1010001;
4096 MCHBAR32(0x1418) = 0x1110000;
4097 MCHBAR32(0x141c) = 0x9020020;
4098 MCHBAR32(0x1420) = 0xd090220;
4099 MCHBAR32(0x1424) = 0x2090220;
4100 MCHBAR32(0x1428) = 0x2090330;
4101 MCHBAR32(0x142c) = 0xd090220;
4102 MCHBAR32(0x1430) = 0x1010001;
4103 MCHBAR32(0x1434) = 0x1110000;
4104 MCHBAR32(0x1438) = 0x11040020;
4105 MCHBAR32(0x143c) = 0x4030220;
4106 MCHBAR32(0x1440) = 0x1060220;
4107 MCHBAR32(0x1444) = 0x1060330;
4108 MCHBAR32(0x1448) = 0x4030220;
4109 MCHBAR32(0x144c) = 0x1010001;
4110 MCHBAR32(0x1450) = 0x1110000;
4111 MCHBAR32(0x1454) = 0x4010020;
4112 MCHBAR32(0x1458) = 0xb090220;
4113 MCHBAR32(0x145c) = 0x1090220;
4114 MCHBAR32(0x1460) = 0x1090330;
4115 MCHBAR32(0x1464) = 0xb090220;
4116 MCHBAR32(0x1468) = 0x1010001;
4117 MCHBAR32(0x146c) = 0x1110000;
4118 MCHBAR32(0x1470) = 0xf040020;
4119 MCHBAR32(0x1474) = 0xa090220;
4120 MCHBAR32(0x1478) = 0x1120220;
4121 MCHBAR32(0x147c) = 0x1120330;
4122 MCHBAR32(0x1480) = 0xa090220;
4123 MCHBAR32(0x1484) = 0x1010001;
4124 MCHBAR32(0x1488) = 0x1110000;
4125 MCHBAR32(0x148c) = 0x7020020;
4126 MCHBAR32(0x1490) = 0x1010220;
4127 MCHBAR32(0x1494) = 0x10210;
4128 MCHBAR32(0x1498) = 0x10320;
4129 MCHBAR32(0x149c) = 0x1010220;
4130 MCHBAR32(0x14a0) = 0x1010001;
4131 MCHBAR32(0x14a4) = 0x1110000;
4132 MCHBAR32(0x14a8) = 0xd040020;
4133 MCHBAR32(0x14ac) = 0x8090220;
4134 MCHBAR32(0x14b0) = 0x1111310;
4135 MCHBAR32(0x14b4) = 0x1111420;
4136 MCHBAR32(0x14b8) = 0x8090220;
4137 MCHBAR32(0x14bc) = 0x1010001;
4138 MCHBAR32(0x14c0) = 0x1110000;
4139 MCHBAR32(0x14c4) = 0x3010020;
4140 MCHBAR32(0x14c8) = 0x7090220;
4141 MCHBAR32(0x14cc) = 0x1081310;
4142 MCHBAR32(0x14d0) = 0x1081420;
4143 MCHBAR32(0x14d4) = 0x7090220;
4144 MCHBAR32(0x14d8) = 0x1010001;
4145 MCHBAR32(0x14dc) = 0x1110000;
4146 MCHBAR32(0x14e0) = 0xb040020;
4147 MCHBAR32(0x14e4) = 0x2030220;
4148 MCHBAR32(0x14e8) = 0x1051310;
4149 MCHBAR32(0x14ec) = 0x1051420;
4150 MCHBAR32(0x14f0) = 0x2030220;
4151 MCHBAR32(0x14f4) = 0x1010001;
4152 MCHBAR32(0x14f8) = 0x1110000;
4153 MCHBAR32(0x14fc) = 0x5020020;
4154 MCHBAR32(0x1500) = 0x5090220;
4155 MCHBAR32(0x1504) = 0x2071310;
4156 MCHBAR32(0x1508) = 0x2071420;
4157 MCHBAR32(0x150c) = 0x5090220;
4158 MCHBAR32(0x1510) = 0x1010001;
4159 MCHBAR32(0x1514) = 0x1110000;
4160 MCHBAR32(0x1518) = 0x7040120;
4161 MCHBAR32(0x151c) = 0x2090220;
4162 MCHBAR32(0x1520) = 0x70b1210;
4163 MCHBAR32(0x1524) = 0x70b1310;
4164 MCHBAR32(0x1528) = 0x2090220;
4165 MCHBAR32(0x152c) = 0x1010001;
4166 MCHBAR32(0x1530) = 0x1110000;
4167 MCHBAR32(0x1534) = 0x1010110;
4168 MCHBAR32(0x1538) = 0x1081310;
4169 MCHBAR32(0x153c) = 0x5041200;
4170 MCHBAR32(0x1540) = 0x5041310;
4171 MCHBAR32(0x1544) = 0x1081310;
4172 MCHBAR32(0x1548) = 0x1010001;
4173 MCHBAR32(0x154c) = 0x1110000;
4174 MCHBAR32(0x1550) = 0x1040120;
4175 MCHBAR32(0x1554) = 0x4051210;
4176 MCHBAR32(0x1558) = 0xd051200;
4177 MCHBAR32(0x155c) = 0xd051200;
4178 MCHBAR32(0x1560) = 0x4051210;
4179 MCHBAR32(0x1564) = 0x1010001;
4180 MCHBAR32(0x1568) = 0x1110000;
4181 MCHBAR16(0x1222) = 0x220a;
4182 MCHBAR16(0x123c) = 0x1fc0;
4183 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004184 }
4185
Felix Heldf83d80b2018-07-29 05:30:30 +02004186 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004187 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004188 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004189
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004190 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004191
4192 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004193 MCHBAR8_AND(0x2ca8, ~3);
4194 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004195 /* This issues a CPU reset without resetting the platform */
4196 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004197 /* Write back the S3 state to PM1_CNT to let the reset CPU
4198 know it also needs to take the s3 path. */
4199 if (s3resume)
4200 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4201 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004202 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004203 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004204 }
4205
Felix Held04be2dd2018-07-29 04:53:22 +02004206 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004207 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004208 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004209 MCHBAR16(0x2c20); // !!!!
4210 MCHBAR16(0x2c10); // !!!!
4211 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004212 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004213 udelay(1000);
4214 write_1d0(0, 0x33d, 0, 0);
4215 write_500(&info, 0, 0, 0xb61, 0, 0);
4216 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004217 MCHBAR32(0x1a30) = 0x0;
4218 MCHBAR32(0x1a34) = 0x0;
4219 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4220 (info.populated_ranks[0][0][0] * 0xa0);
4221 MCHBAR16(0x616) = 0x26a;
4222 MCHBAR32(0x134) = 0x856000;
4223 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004224 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4225 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004226 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004227 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4228 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004229 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004230 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004231 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4232 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004233 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4234 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4235 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4236 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4237 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4238 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4239 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4240 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4241 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4242 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004243 }
4244
4245 write_1d0(0x4, 0x151, 4, 1);
4246 write_1d0(0, 0x142, 3, 1);
4247 rdmsr(0x1ac); // !!!!
4248 write_500(&info, 1, 1, 0x6b3, 4, 1);
4249 write_500(&info, 1, 1, 0x6cf, 4, 1);
4250
4251 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4252
4253 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4254 populated_ranks[0]
4255 [0][0]) << 0),
4256 0x1d1, 3, 1);
4257 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4259 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004260 }
4261
4262 set_334(0);
4263
4264 program_base_timings(&info);
4265
Felix Held04be2dd2018-07-29 04:53:22 +02004266 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004267
4268 write_1d0(0x2, 0x1d5, 2, 1);
4269 write_1d0(0x20, 0x166, 7, 1);
4270 write_1d0(0x0, 0xeb, 3, 1);
4271 write_1d0(0x0, 0xf3, 6, 1);
4272
4273 for (channel = 0; channel < NUM_CHANNELS; channel++)
4274 for (lane = 0; lane < 9; lane++) {
4275 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4276 u8 a;
4277 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4278 write_500(&info, channel, a, addr, 6, 1);
4279 }
4280
4281 udelay(1000);
4282
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004283 if (s3resume) {
4284 if (info.cached_training == NULL) {
4285 u32 reg32;
4286 printk(BIOS_ERR,
4287 "Couldn't find training data. Rebooting\n");
4288 reg32 = inl(DEFAULT_PMBASE + 0x04);
4289 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004290 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004291 }
4292 int tm;
4293 info.training = *info.cached_training;
4294 for (tm = 0; tm < 4; tm++)
4295 for (channel = 0; channel < NUM_CHANNELS; channel++)
4296 for (slot = 0; slot < NUM_SLOTS; slot++)
4297 for (rank = 0; rank < NUM_RANKS; rank++)
4298 for (lane = 0; lane < 9; lane++)
4299 write_500(&info,
4300 channel,
4301 info.training.
4302 lane_timings
4303 [tm][channel]
4304 [slot][rank]
4305 [lane],
4306 get_timing_register_addr
4307 (lane, tm,
4308 slot, rank),
4309 9, 0);
4310 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4311 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4312 }
4313
Felix Heldf83d80b2018-07-29 05:30:30 +02004314 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004315 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004316 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004317 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004318
4319 program_board_delay(&info);
4320
Felix Held04be2dd2018-07-29 04:53:22 +02004321 MCHBAR8(0x5ff) = 0x0;
4322 MCHBAR8(0x5ff) = 0x80;
4323 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004324
Felix Held04be2dd2018-07-29 04:53:22 +02004325 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004326 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004327 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004328 gav(read_1d0(0x14b, 7)); // = 0x81023100
4329 write_1d0(0x30, 0x14b, 7, 1);
4330 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4331 write_1d0(7, 0xd6, 6, 1);
4332 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4333 write_1d0(7, 0x328, 6, 1);
4334
4335 for (channel = 0; channel < NUM_CHANNELS; channel++)
4336 set_4cf(&info, channel,
4337 info.populated_ranks[channel][0][0] ? 8 : 0);
4338
4339 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4340 write_1d0(2, 0x116, 4, 1);
4341 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4342 write_1d0(0, 0xae, 6, 1);
4343 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4344 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004345 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4346 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004347 MCHBAR32_AND(0x140, ~0x07000000);
4348 MCHBAR32_AND(0x138, ~0x07000000);
4349 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004350 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004351 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004352 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004353
4354 {
4355 u32 t;
4356 u8 val_a1;
4357 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4358 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4359 rmw_1d0(0x320, 0x07,
4360 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4361 rmw_1d0(0x14b, 0x78,
4362 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4363 4), 7,
4364 1);
4365 rmw_1d0(0xce, 0x38,
4366 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4367 4), 6,
4368 1);
4369 }
4370
4371 for (channel = 0; channel < NUM_CHANNELS; channel++)
4372 set_4cf(&info, channel,
4373 info.populated_ranks[channel][0][0] ? 9 : 1);
4374
4375 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004376 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004377 write_1d0(2, 0xae, 6, 1);
4378 write_1d0(2, 0x300, 6, 1);
4379 write_1d0(2, 0x121, 3, 1);
4380 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4381 write_1d0(4, 0xd6, 6, 1);
4382 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4383 write_1d0(4, 0x328, 6, 1);
4384
4385 for (channel = 0; channel < NUM_CHANNELS; channel++)
4386 set_4cf(&info, channel,
4387 info.populated_ranks[channel][0][0] ? 9 : 0);
4388
Felix Held04be2dd2018-07-29 04:53:22 +02004389 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4390 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004391 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004392 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004393 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4394 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4395 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4396 write_1d0(0, 0x21c, 6, 1);
4397 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4398 write_1d0(0x35, 0x14b, 7, 1);
4399
4400 for (channel = 0; channel < NUM_CHANNELS; channel++)
4401 set_4cf(&info, channel,
4402 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4403
4404 set_334(1);
4405
Felix Held04be2dd2018-07-29 04:53:22 +02004406 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004407
4408 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4409 write_500(&info, channel,
4410 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4411 1);
4412 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4413 }
Felix Held04be2dd2018-07-29 04:53:22 +02004414 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4415 MCHBAR16(0x6c0) = 0x14a0;
4416 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4417 MCHBAR16(0x232) = 0x8;
4418 /* 0x40004 or 0 depending on ? */
4419 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4420 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4421 MCHBAR32(0x128) = 0x2150d05;
4422 MCHBAR8(0x12c) = 0x1f;
4423 MCHBAR8(0x12d) = 0x56;
4424 MCHBAR8(0x12e) = 0x31;
4425 MCHBAR8(0x12f) = 0x0;
4426 MCHBAR8(0x271) = 0x2;
4427 MCHBAR8(0x671) = 0x2;
4428 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004429 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004430 MCHBAR32(0x294 + (channel << 10)) =
4431 (info.populated_ranks_mask[channel] & 3) << 16;
4432 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4433 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004434 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004435 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4436 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004437
4438 if (!s3resume)
4439 jedec_init(&info);
4440
4441 int totalrank = 0;
4442 for (channel = 0; channel < NUM_CHANNELS; channel++)
4443 for (slot = 0; slot < NUM_SLOTS; slot++)
4444 for (rank = 0; rank < NUM_RANKS; rank++)
4445 if (info.populated_ranks[channel][slot][rank]) {
4446 jedec_read(&info, channel, slot, rank,
4447 totalrank, 0xa, 0x400);
4448 totalrank++;
4449 }
4450
Felix Held04be2dd2018-07-29 04:53:22 +02004451 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004452
Felix Heldf83d80b2018-07-29 05:30:30 +02004453 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4454 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004455
4456 if (!s3resume) {
4457 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004458 MCHBAR32(0x294 + (channel << 10)) =
4459 (info.populated_ranks_mask[channel] & 3) << 16;
4460 MCHBAR16(0x298 + (channel << 10)) =
4461 info.populated_ranks[channel][0][0] |
4462 (info.populated_ranks[channel][0][1] << 5);
4463 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004464 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004465 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004466
4467 {
4468 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004469 a = MCHBAR8(0x243);
4470 b = MCHBAR8(0x643);
4471 MCHBAR8(0x243) = a | 2;
4472 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004473 }
4474
4475 write_1d0(7, 0x19b, 3, 1);
4476 write_1d0(7, 0x1c0, 3, 1);
4477 write_1d0(4, 0x1c6, 4, 1);
4478 write_1d0(4, 0x1cc, 4, 1);
4479 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4480 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004481 MCHBAR32(0x584) = 0xfffff;
4482 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004483
4484 for (channel = 0; channel < NUM_CHANNELS; channel++)
4485 for (slot = 0; slot < NUM_SLOTS; slot++)
4486 for (rank = 0; rank < NUM_RANKS; rank++)
4487 if (info.
4488 populated_ranks[channel][slot]
4489 [rank])
4490 config_rank(&info, s3resume,
4491 channel, slot,
4492 rank);
4493
Felix Held04be2dd2018-07-29 04:53:22 +02004494 MCHBAR8(0x243) = 0x1;
4495 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004496 }
4497
4498 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004499 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004500 write_26c(0, 0x820);
4501 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004502 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004503 /* end */
4504
4505 if (s3resume) {
4506 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004507 MCHBAR32(0x294 + (channel << 10)) =
4508 (info.populated_ranks_mask[channel] & 3) << 16;
4509 MCHBAR16(0x298 + (channel << 10)) =
4510 info.populated_ranks[channel][0][0] |
4511 (info.populated_ranks[channel][0][1] << 5);
4512 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004514 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004515 }
4516
Felix Held04be2dd2018-07-29 04:53:22 +02004517 MCHBAR32_AND(0xfa4, ~0x01000002);
4518 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 /* Before training. */
4521 timestamp_add_now(103);
4522
4523 if (!s3resume)
4524 ram_training(&info);
4525
4526 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004527 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004528
4529 dump_timings(&info);
4530
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 program_modules_memory_map(&info, 0);
4532 program_total_memory_map(&info);
4533
4534 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004535 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004536 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004537 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004538 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004539 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540 else
Felix Held04be2dd2018-07-29 04:53:22 +02004541 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004542
Felix Held04be2dd2018-07-29 04:53:22 +02004543 MCHBAR32_AND(0xfac, ~0x80000000);
4544 MCHBAR32(0xfb4) = 0x4800;
4545 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4546 MCHBAR32(0xe94) = 0x7ffff;
4547 MCHBAR32(0xfc0) = 0x80002040;
4548 MCHBAR32(0xfc4) = 0x701246;
4549 MCHBAR8_AND(0xfc8, ~0x70);
4550 MCHBAR32_OR(0xe5c, 0x1000000);
4551 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4552 MCHBAR32(0x50) = 0x700b0;
4553 MCHBAR32(0x3c) = 0x10;
4554 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4555 MCHBAR8_OR(0xff4, 0x2);
4556 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557
Felix Held04be2dd2018-07-29 04:53:22 +02004558 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4559 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4560 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004562 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4563 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4564 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004565
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 {
4567 u32 eax;
4568
4569 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004570 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4571 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4572 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573 }
4574
4575 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004576 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 else
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583
Felix Held04be2dd2018-07-29 04:53:22 +02004584 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004586 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587 else
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 }
4590
Felix Held04be2dd2018-07-29 04:53:22 +02004591 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592
4593 {
4594 u8 al;
4595 al = 0xd;
4596 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4597 al += 2;
4598 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600 }
4601
4602 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004603 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4604 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4605 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4606 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004607 }
4608 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004609 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004610 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004611 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004612 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004613 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004614 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004615 MCHBAR8_OR(0x1210, 2);
4616 MCHBAR32(0x1200) = 0x8800440;
4617 MCHBAR32(0x1204) = 0x53ff0453;
4618 MCHBAR32(0x1208) = 0x19002043;
4619 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004620
4621 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004622 MCHBAR16(0x1214) = 0x220;
4623 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624 }
4625
Felix Held04be2dd2018-07-29 04:53:22 +02004626 MCHBAR8_OR(0x1214, 0x4);
4627 MCHBAR8(0x120c) = 0x1;
4628 MCHBAR8(0x1218) = 0x3;
4629 MCHBAR8(0x121a) = 0x3;
4630 MCHBAR8(0x121c) = 0x3;
4631 MCHBAR16(0xc14) = 0x0;
4632 MCHBAR16(0xc20) = 0x0;
4633 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
4635 /* revision dependent here. */
4636
Felix Held04be2dd2018-07-29 04:53:22 +02004637 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638
4639 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR16_OR(0x1230, 0x8000);
4643 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644
4645 u8 bl, ebpb;
4646 u16 reg_1020;
4647
Felix Held04be2dd2018-07-29 04:53:22 +02004648 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4649 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004650
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR32(0x1000) = 0x100;
4652 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653
4654 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004655 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004656 bl = reg_1020 >> 8;
4657 ebpb = reg_1020 & 0xff;
4658 } else {
4659 ebpb = 0;
4660 bl = 8;
4661 }
4662
4663 rdmsr(0x1a2);
4664
Felix Held04be2dd2018-07-29 04:53:22 +02004665 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004666
Felix Held04be2dd2018-07-29 04:53:22 +02004667 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004668
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004670
Felix Held04be2dd2018-07-29 04:53:22 +02004671 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004672 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004673 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4674 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675 }
4676
4677 setup_heci_uma(&info);
4678
4679 if (info.uma_enabled) {
4680 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR32_OR(0x11b0, 0x4000);
4682 MCHBAR32_OR(0x11b4, 0x4000);
4683 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684
Felix Held04be2dd2018-07-29 04:53:22 +02004685 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4686 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4687 MCHBAR16_OR(0x1170, 0x1000);
4688
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004689 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004690
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004692 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004693 ;
4694 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 }
4696
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004697 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4698 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004700 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004702 udelay(1000);
4703 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004704 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4705
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706 if (!s3resume)
4707 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004708 if (s3resume && cbmem_wasnot_inited) {
4709 u32 reg32;
4710 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004711 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004712
4713 /* Clear SLP_TYPE. */
4714 reg32 = inl(DEFAULT_PMBASE + 0x04);
4715 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4716
4717 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004718 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004719 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720}