blob: 7bb95efe6460d048454bf8991bd35fe565ef68e2 [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
Angel Ponsc10f8b22021-01-15 20:34:51 +0100263static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
264{
265 const u32 val = read_500(info, channel, addr, bits) & and;
266 write_500(info, channel, val | or, addr, bits, 1);
267}
268
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100269static int rw_test(int rank)
270{
271 const u32 mask = 0xf00fc33c;
272 int ok = 0xff;
273 int i;
274 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800275 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276 sfence();
277 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800278 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100279 sfence();
280 for (i = 0; i < 32; i++) {
281 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 write32p((rank << 28) | (i << 3), pat);
283 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100284 }
285 sfence();
286 for (i = 0; i < 32; i++) {
287 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
288 int j;
289 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800290 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291 for (j = 0; j < 4; j++)
292 if (((val >> (j * 8)) & 0xff) != pat)
293 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(16 << j);
298 }
299 sfence();
300 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800301 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100302 sfence();
303 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800304 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100305
306 return ok;
307}
308
309static void
310program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
311{
312 int lane;
313 for (lane = 0; lane < 8; lane++) {
314 write_500(info, channel,
315 base +
316 info->training.
317 lane_timings[2][channel][slot][rank][lane],
318 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
319 write_500(info, channel,
320 base +
321 info->training.
322 lane_timings[3][channel][slot][rank][lane],
323 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
324 }
325}
326
327static void write_26c(int channel, u16 si)
328{
Felix Held04be2dd2018-07-29 04:53:22 +0200329 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
330 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
331 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332}
333
334static u32 get_580(int channel, u8 addr)
335{
336 u32 ret;
337 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200338 MCHBAR8(0x5ff) = 0x0;
339 MCHBAR8(0x5ff) = 0x80;
340 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
341 MCHBAR8_OR(0x580 + (channel << 10), 1);
342 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
343 ;
344 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100345 return ret;
346}
347
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100348#define NUM_CHANNELS 2
349#define NUM_SLOTS 2
350#define NUM_RANKS 2
351#define RANK_SHIFT 28
352#define CHANNEL_SHIFT 10
353
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100354static void seq9(struct raminfo *info, int channel, int slot, int rank)
355{
356 int i, lane;
357
358 for (i = 0; i < 2; i++)
359 for (lane = 0; lane < 8; lane++)
360 write_500(info, channel,
361 info->training.lane_timings[i +
362 1][channel][slot]
363 [rank][lane], get_timing_register_addr(lane,
364 i + 1,
365 slot,
366 rank),
367 9, 0);
368
369 write_1d0(1, 0x103, 6, 1);
370 for (lane = 0; lane < 8; lane++)
371 write_500(info, channel,
372 info->training.
373 lane_timings[0][channel][slot][rank][lane],
374 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
375
376 for (i = 0; i < 2; i++) {
377 for (lane = 0; lane < 8; lane++)
378 write_500(info, channel,
379 info->training.lane_timings[i +
380 1][channel][slot]
381 [rank][lane], get_timing_register_addr(lane,
382 i + 1,
383 slot,
384 rank),
385 9, 0);
386 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
387 }
388
389 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200390 MCHBAR8(0x5ff) = 0x0;
391 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100392 write_1d0(0x2, 0x142, 3, 1);
393 for (lane = 0; lane < 8; lane++) {
394 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
395 info->training.lane_timings[2][channel][slot][rank][lane] =
396 read_500(info, channel,
397 get_timing_register_addr(lane, 2, slot, rank), 9);
398 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
399 info->training.lane_timings[3][channel][slot][rank][lane] =
400 info->training.lane_timings[2][channel][slot][rank][lane] +
401 0x20;
402 }
403}
404
405static int count_ranks_in_channel(struct raminfo *info, int channel)
406{
407 int slot, rank;
408 int res = 0;
409 for (slot = 0; slot < NUM_SLOTS; slot++)
410 for (rank = 0; rank < NUM_SLOTS; rank++)
411 res += info->populated_ranks[channel][slot][rank];
412 return res;
413}
414
415static void
416config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
417{
418 int add;
419
420 write_1d0(0, 0x178, 7, 1);
421 seq9(info, channel, slot, rank);
422 program_timings(info, 0x80, channel, slot, rank);
423
424 if (channel == 0)
425 add = count_ranks_in_channel(info, 1);
426 else
427 add = 0;
428 if (!s3resume)
429 gav(rw_test(rank + add));
430 program_timings(info, 0x00, channel, slot, rank);
431 if (!s3resume)
432 gav(rw_test(rank + add));
433 if (!s3resume)
434 gav(rw_test(rank + add));
435 write_1d0(0, 0x142, 3, 1);
436 write_1d0(0, 0x103, 6, 1);
437
438 gav(get_580(channel, 0xc | (rank << 5)));
439 gav(read_1d0(0x142, 3));
440
Felix Held04be2dd2018-07-29 04:53:22 +0200441 MCHBAR8(0x5ff) = 0x0;
442 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100443}
444
Angel Ponsc10f8b22021-01-15 20:34:51 +0100445static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100446{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100447 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
448
449 val &= 1;
450 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
451 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100452}
453
454static void set_334(int zero)
455{
456 int j, k, channel;
457 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
458 u32 vd8[2][16];
459
460 for (channel = 0; channel < NUM_CHANNELS; channel++) {
461 for (j = 0; j < 4; j++) {
462 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
463 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
464 u16 c;
465 if ((j == 0 || j == 3) && zero)
466 c = 0;
467 else if (j == 3)
468 c = 0x5f;
469 else
470 c = 0x5f5f;
471
472 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200473 MCHBAR32(0x138 + 8 * k) =
474 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100475 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200476 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100477 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200478 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100479 }
480
Felix Held22ca8cb2018-07-29 05:09:44 +0200481 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
482 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200483 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
484 zero ? 0 : (0x18191819 & lmask);
485 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
486 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
487 zero ? 0 : (a & lmask);
488 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
489 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100490 }
491 }
492
Felix Held04be2dd2018-07-29 04:53:22 +0200493 MCHBAR32_OR(0x130, 1);
494 while (MCHBAR8(0x130) & 1)
495 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100496}
497
Angel Pons244f4552021-01-15 20:41:36 +0100498static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499{
500 u32 v;
501 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100502 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100503}
504
505static int find_highest_bit_set(u16 val)
506{
507 int i;
508 for (i = 15; i >= 0; i--)
509 if (val & (1 << i))
510 return i;
511 return -1;
512}
513
514static int find_lowest_bit_set32(u32 val)
515{
516 int i;
517 for (i = 0; i < 32; i++)
518 if (val & (1 << i))
519 return i;
520 return -1;
521}
522
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100523enum {
524 DEVICE_TYPE = 2,
525 MODULE_TYPE = 3,
526 DENSITY = 4,
527 RANKS_AND_DQ = 7,
528 MEMORY_BUS_WIDTH = 8,
529 TIMEBASE_DIVIDEND = 10,
530 TIMEBASE_DIVISOR = 11,
531 CYCLETIME = 12,
532
533 CAS_LATENCIES_LSB = 14,
534 CAS_LATENCIES_MSB = 15,
535 CAS_LATENCY_TIME = 16,
536 THERMAL_AND_REFRESH = 31,
537 REFERENCE_RAW_CARD_USED = 62,
538 RANK1_ADDRESS_MAPPING = 63
539};
540
541static void calculate_timings(struct raminfo *info)
542{
Martin Roth468d02c2019-10-23 21:44:42 -0600543 unsigned int cycletime;
544 unsigned int cas_latency_time;
545 unsigned int supported_cas_latencies;
546 unsigned int channel, slot;
547 unsigned int clock_speed_index;
548 unsigned int min_cas_latency;
549 unsigned int cas_latency;
550 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100551
552 /* Find common CAS latency */
553 supported_cas_latencies = 0x3fe;
554 for (channel = 0; channel < NUM_CHANNELS; channel++)
555 for (slot = 0; slot < NUM_SLOTS; slot++)
556 if (info->populated_ranks[channel][slot][0])
557 supported_cas_latencies &=
558 2 *
559 (info->
560 spd[channel][slot][CAS_LATENCIES_LSB] |
561 (info->
562 spd[channel][slot][CAS_LATENCIES_MSB] <<
563 8));
564
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100565 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100566
567 cycletime = min_cycletime[max_clock_index];
568 cas_latency_time = min_cas_latency_time[max_clock_index];
569
570 for (channel = 0; channel < NUM_CHANNELS; channel++)
571 for (slot = 0; slot < NUM_SLOTS; slot++)
572 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600573 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100574 timebase =
575 1000 *
576 info->
577 spd[channel][slot][TIMEBASE_DIVIDEND] /
578 info->spd[channel][slot][TIMEBASE_DIVISOR];
579 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100580 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100581 timebase *
582 info->spd[channel][slot][CYCLETIME]);
583 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100584 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100585 timebase *
586 info->
587 spd[channel][slot][CAS_LATENCY_TIME]);
588 }
Jacob Garber3c193822019-06-10 18:23:32 -0600589 if (cycletime > min_cycletime[0])
590 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100591 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
592 if (cycletime == min_cycletime[clock_speed_index])
593 break;
594 if (cycletime > min_cycletime[clock_speed_index]) {
595 clock_speed_index--;
596 cycletime = min_cycletime[clock_speed_index];
597 break;
598 }
599 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100600 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100601 cas_latency = 0;
602 while (supported_cas_latencies) {
603 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
604 if (cas_latency <= min_cas_latency)
605 break;
606 supported_cas_latencies &=
607 ~(1 << find_highest_bit_set(supported_cas_latencies));
608 }
609
610 if (cas_latency != min_cas_latency && clock_speed_index)
611 clock_speed_index--;
612
613 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
614 die("Couldn't configure DRAM");
615 info->clock_speed_index = clock_speed_index;
616 info->cas_latency = cas_latency;
617}
618
619static void program_base_timings(struct raminfo *info)
620{
Martin Roth468d02c2019-10-23 21:44:42 -0600621 unsigned int channel;
622 unsigned int slot, rank, lane;
623 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100624 int i;
625
626 extended_silicon_revision = info->silicon_revision;
627 if (info->silicon_revision == 0)
628 for (channel = 0; channel < NUM_CHANNELS; channel++)
629 for (slot = 0; slot < NUM_SLOTS; slot++)
630 if ((info->
631 spd[channel][slot][MODULE_TYPE] & 0xF) ==
632 3)
633 extended_silicon_revision = 4;
634
635 for (channel = 0; channel < NUM_CHANNELS; channel++) {
636 for (slot = 0; slot < NUM_SLOTS; slot++)
637 for (rank = 0; rank < NUM_SLOTS; rank++) {
638 int card_timing_2;
639 if (!info->populated_ranks[channel][slot][rank])
640 continue;
641
642 for (lane = 0; lane < 9; lane++) {
643 int tm_reg;
644 int card_timing;
645
646 card_timing = 0;
647 if ((info->
648 spd[channel][slot][MODULE_TYPE] &
649 0xF) == 3) {
650 int reference_card;
651 reference_card =
652 info->
653 spd[channel][slot]
654 [REFERENCE_RAW_CARD_USED] &
655 0x1f;
656 if (reference_card == 3)
657 card_timing =
658 u16_ffd1188[0][lane]
659 [info->
660 clock_speed_index];
661 if (reference_card == 5)
662 card_timing =
663 u16_ffd1188[1][lane]
664 [info->
665 clock_speed_index];
666 }
667
668 info->training.
669 lane_timings[0][channel][slot][rank]
670 [lane] =
671 u8_FFFD1218[info->
672 clock_speed_index];
673 info->training.
674 lane_timings[1][channel][slot][rank]
675 [lane] = 256;
676
677 for (tm_reg = 2; tm_reg < 4; tm_reg++)
678 info->training.
679 lane_timings[tm_reg]
680 [channel][slot][rank][lane]
681 =
682 u8_FFFD1240[channel]
683 [extended_silicon_revision]
684 [lane][2 * slot +
685 rank][info->
686 clock_speed_index]
687 + info->max4048[channel]
688 +
689 u8_FFFD0C78[channel]
690 [extended_silicon_revision]
691 [info->
692 mode4030[channel]][slot]
693 [rank][info->
694 clock_speed_index]
695 + card_timing;
696 for (tm_reg = 0; tm_reg < 4; tm_reg++)
697 write_500(info, channel,
698 info->training.
699 lane_timings[tm_reg]
700 [channel][slot][rank]
701 [lane],
702 get_timing_register_addr
703 (lane, tm_reg, slot,
704 rank), 9, 0);
705 }
706
707 card_timing_2 = 0;
708 if (!(extended_silicon_revision != 4
709 || (info->
710 populated_ranks_mask[channel] & 5) ==
711 5)) {
712 if ((info->
713 spd[channel][slot]
714 [REFERENCE_RAW_CARD_USED] & 0x1F)
715 == 3)
716 card_timing_2 =
717 u16_FFFE0EB8[0][info->
718 clock_speed_index];
719 if ((info->
720 spd[channel][slot]
721 [REFERENCE_RAW_CARD_USED] & 0x1F)
722 == 5)
723 card_timing_2 =
724 u16_FFFE0EB8[1][info->
725 clock_speed_index];
726 }
727
728 for (i = 0; i < 3; i++)
729 write_500(info, channel,
730 (card_timing_2 +
731 info->max4048[channel]
732 +
733 u8_FFFD0EF8[channel]
734 [extended_silicon_revision]
735 [info->
736 mode4030[channel]][info->
737 clock_speed_index]),
738 u16_fffd0c50[i][slot][rank],
739 8, 1);
740 write_500(info, channel,
741 (info->max4048[channel] +
742 u8_FFFD0C78[channel]
743 [extended_silicon_revision][info->
744 mode4030
745 [channel]]
746 [slot][rank][info->
747 clock_speed_index]),
748 u16_fffd0c70[slot][rank], 7, 1);
749 }
750 if (!info->populated_ranks_mask[channel])
751 continue;
752 for (i = 0; i < 3; i++)
753 write_500(info, channel,
754 (info->max4048[channel] +
755 info->avg4044[channel]
756 +
757 u8_FFFD17E0[channel]
758 [extended_silicon_revision][info->
759 mode4030
760 [channel]][info->
761 clock_speed_index]),
762 u16_fffd0c68[i], 8, 1);
763 }
764}
765
766static unsigned int fsbcycle_ps(struct raminfo *info)
767{
768 return 900000 / info->fsb_frequency;
769}
770
771/* The time of DDR transfer in ps. */
772static unsigned int halfcycle_ps(struct raminfo *info)
773{
774 return 3750 / (info->clock_speed_index + 3);
775}
776
777/* The time of clock cycle in ps. */
778static unsigned int cycle_ps(struct raminfo *info)
779{
780 return 2 * halfcycle_ps(info);
781}
782
783/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600784static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100785{
786 return (info->clock_speed_index + 3) * 120;
787}
788
789/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600790static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100791{
792 return 100 * frequency_11(info) / 9;
793}
794
Martin Roth468d02c2019-10-23 21:44:42 -0600795static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100796{
797 return (frequency_11(info) * 2) * ps / 900000;
798}
799
Martin Roth468d02c2019-10-23 21:44:42 -0600800static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100801{
802 return (frequency_11(info)) * ns / 900;
803}
804
805static void compute_derived_timings(struct raminfo *info)
806{
Martin Roth468d02c2019-10-23 21:44:42 -0600807 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100808 int extended_silicon_revision;
809 int some_delay_1_ps;
810 int some_delay_2_ps;
811 int some_delay_2_halfcycles_ceil;
812 int some_delay_2_halfcycles_floor;
813 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100814 int some_delay_3_ps_rounded;
815 int some_delay_1_cycle_ceil;
816 int some_delay_1_cycle_floor;
817
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100818 some_delay_3_ps_rounded = 0;
819 extended_silicon_revision = info->silicon_revision;
820 if (!info->silicon_revision)
821 for (channel = 0; channel < NUM_CHANNELS; channel++)
822 for (slot = 0; slot < NUM_SLOTS; slot++)
823 if ((info->
824 spd[channel][slot][MODULE_TYPE] & 0xF) ==
825 3)
826 extended_silicon_revision = 4;
827 if (info->board_lane_delay[7] < 5)
828 info->board_lane_delay[7] = 5;
829 info->revision_flag_1 = 2;
830 if (info->silicon_revision == 2 || info->silicon_revision == 3)
831 info->revision_flag_1 = 0;
832 if (info->revision < 16)
833 info->revision_flag_1 = 0;
834
835 if (info->revision < 8)
836 info->revision_flag_1 = 0;
837 if (info->revision >= 8 && (info->silicon_revision == 0
838 || info->silicon_revision == 1))
839 some_delay_2_ps = 735;
840 else
841 some_delay_2_ps = 750;
842
843 if (info->revision >= 0x10 && (info->silicon_revision == 0
844 || info->silicon_revision == 1))
845 some_delay_1_ps = 3929;
846 else
847 some_delay_1_ps = 3490;
848
849 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
850 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
851 if (some_delay_1_ps % cycle_ps(info))
852 some_delay_1_cycle_ceil++;
853 else
854 some_delay_1_cycle_floor--;
855 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
856 if (info->revision_flag_1)
857 some_delay_2_ps = halfcycle_ps(info) >> 6;
858 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100859 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100860 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
861 375;
862 some_delay_3_ps =
863 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
864 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200865 if (some_delay_3_ps >= 150) {
866 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100867 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200868 some_delay_3_ps_rounded =
869 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
870 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100871 }
872 some_delay_2_halfcycles_ceil =
873 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
874 2 * (some_delay_1_cycle_ceil - 1);
875 if (info->revision_flag_1 && some_delay_3_ps < 150)
876 some_delay_2_halfcycles_ceil++;
877 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
878 if (info->revision < 0x10)
879 some_delay_2_halfcycles_floor =
880 some_delay_2_halfcycles_ceil - 1;
881 if (!info->revision_flag_1)
882 some_delay_2_halfcycles_floor++;
883 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
884 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
885 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
886 || (info->populated_ranks[1][0][0]
887 && info->populated_ranks[1][1][0]))
888 info->max_slots_used_in_channel = 2;
889 else
890 info->max_slots_used_in_channel = 1;
891 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200892 MCHBAR32(0x244 + (channel << 10)) =
893 ((info->revision < 8) ? 1 : 0x200) |
894 ((2 - info->max_slots_used_in_channel) << 17) |
895 (channel << 21) |
896 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100897 if (info->max_slots_used_in_channel == 1) {
898 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
899 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
900 } else {
901 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 */
902 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
903 || (count_ranks_in_channel(info, 1) ==
904 2)) ? 2 : 3;
905 }
906 for (channel = 0; channel < NUM_CHANNELS; channel++) {
907 int max_of_unk;
908 int min_of_unk_2;
909
910 int i, count;
911 int sum;
912
913 if (!info->populated_ranks_mask[channel])
914 continue;
915
916 max_of_unk = 0;
917 min_of_unk_2 = 32767;
918
919 sum = 0;
920 count = 0;
921 for (i = 0; i < 3; i++) {
922 int unk1;
923 if (info->revision < 8)
924 unk1 =
925 u8_FFFD1891[0][channel][info->
926 clock_speed_index]
927 [i];
928 else if (!
929 (info->revision >= 0x10
930 || info->revision_flag_1))
931 unk1 =
932 u8_FFFD1891[1][channel][info->
933 clock_speed_index]
934 [i];
935 else
936 unk1 = 0;
937 for (slot = 0; slot < NUM_SLOTS; slot++)
938 for (rank = 0; rank < NUM_RANKS; rank++) {
939 int a = 0;
940 int b = 0;
941
942 if (!info->
943 populated_ranks[channel][slot]
944 [rank])
945 continue;
946 if (extended_silicon_revision == 4
947 && (info->
948 populated_ranks_mask[channel] &
949 5) != 5) {
950 if ((info->
951 spd[channel][slot]
952 [REFERENCE_RAW_CARD_USED] &
953 0x1F) == 3) {
954 a = u16_ffd1178[0]
955 [info->
956 clock_speed_index];
957 b = u16_fe0eb8[0][info->
958 clock_speed_index];
959 } else
960 if ((info->
961 spd[channel][slot]
962 [REFERENCE_RAW_CARD_USED]
963 & 0x1F) == 5) {
964 a = u16_ffd1178[1]
965 [info->
966 clock_speed_index];
967 b = u16_fe0eb8[1][info->
968 clock_speed_index];
969 }
970 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100971 min_of_unk_2 = MIN(min_of_unk_2, a);
972 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100973 if (rank == 0) {
974 sum += a;
975 count++;
976 }
977 {
978 int t;
979 t = b +
980 u8_FFFD0EF8[channel]
981 [extended_silicon_revision]
982 [info->
983 mode4030[channel]][info->
984 clock_speed_index];
985 if (unk1 >= t)
986 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100987 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100988 unk1 - t);
989 }
990 }
991 {
992 int t =
993 u8_FFFD17E0[channel]
994 [extended_silicon_revision][info->
995 mode4030
996 [channel]]
997 [info->clock_speed_index] + min_of_unk_2;
998 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100999 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001000 }
1001 }
1002
Jacob Garber64fb4a32019-06-10 17:29:18 -06001003 if (count == 0)
1004 die("No memory ranks found for channel %u\n", channel);
1005
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001006 info->avg4044[channel] = sum / count;
1007 info->max4048[channel] = max_of_unk;
1008 }
1009}
1010
1011static void jedec_read(struct raminfo *info,
1012 int channel, int slot, int rank,
1013 int total_rank, u8 addr3, unsigned int value)
1014{
1015 /* Handle mirrored mapping. */
1016 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001017 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1018 ((addr3 >> 1) & 0x10);
1019 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1020 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001021
1022 /* Handle mirrored mapping. */
1023 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1024 value =
1025 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1026 << 1);
1027
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001028 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001029
Felix Held04be2dd2018-07-29 04:53:22 +02001030 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1031 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001032
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001033 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001034}
1035
1036enum {
1037 MR1_RZQ12 = 512,
1038 MR1_RZQ2 = 64,
1039 MR1_RZQ4 = 4,
1040 MR1_ODS34OHM = 2
1041};
1042
1043enum {
1044 MR0_BT_INTERLEAVED = 8,
1045 MR0_DLL_RESET_ON = 256
1046};
1047
1048enum {
1049 MR2_RTT_WR_DISABLED = 0,
1050 MR2_RZQ2 = 1 << 10
1051};
1052
1053static void jedec_init(struct raminfo *info)
1054{
1055 int write_recovery;
1056 int channel, slot, rank;
1057 int total_rank;
1058 int dll_on;
1059 int self_refresh_temperature;
1060 int auto_self_refresh;
1061
1062 auto_self_refresh = 1;
1063 self_refresh_temperature = 1;
1064 if (info->board_lane_delay[3] <= 10) {
1065 if (info->board_lane_delay[3] <= 8)
1066 write_recovery = info->board_lane_delay[3] - 4;
1067 else
1068 write_recovery = 5;
1069 } else {
1070 write_recovery = 6;
1071 }
1072 FOR_POPULATED_RANKS {
1073 auto_self_refresh &=
1074 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1075 self_refresh_temperature &=
1076 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1077 }
1078 if (auto_self_refresh == 1)
1079 self_refresh_temperature = 0;
1080
1081 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1082 || (info->populated_ranks[0][0][0]
1083 && info->populated_ranks[0][1][0])
1084 || (info->populated_ranks[1][0][0]
1085 && info->populated_ranks[1][1][0]));
1086
1087 total_rank = 0;
1088
1089 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1090 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1091 int rzq_reg58e;
1092
1093 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1094 rzq_reg58e = 64;
1095 rtt = MR1_RZQ2;
1096 if (info->clock_speed_index != 0) {
1097 rzq_reg58e = 4;
1098 if (info->populated_ranks_mask[channel] == 3)
1099 rtt = MR1_RZQ4;
1100 }
1101 } else {
1102 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1103 rtt = MR1_RZQ12;
1104 rzq_reg58e = 64;
1105 rtt_wr = MR2_RZQ2;
1106 } else {
1107 rzq_reg58e = 4;
1108 rtt = MR1_RZQ4;
1109 }
1110 }
1111
Felix Held04be2dd2018-07-29 04:53:22 +02001112 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1113 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1114 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1115 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1116 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001117
1118 for (slot = 0; slot < NUM_SLOTS; slot++)
1119 for (rank = 0; rank < NUM_RANKS; rank++)
1120 if (info->populated_ranks[channel][slot][rank]) {
1121 jedec_read(info, channel, slot, rank,
1122 total_rank, 0x28,
1123 rtt_wr | (info->
1124 clock_speed_index
1125 << 3)
1126 | (auto_self_refresh << 6) |
1127 (self_refresh_temperature <<
1128 7));
1129 jedec_read(info, channel, slot, rank,
1130 total_rank, 0x38, 0);
1131 jedec_read(info, channel, slot, rank,
1132 total_rank, 0x18,
1133 rtt | MR1_ODS34OHM);
1134 jedec_read(info, channel, slot, rank,
1135 total_rank, 6,
1136 (dll_on << 12) |
1137 (write_recovery << 9)
1138 | ((info->cas_latency - 4) <<
1139 4) | MR0_BT_INTERLEAVED |
1140 MR0_DLL_RESET_ON);
1141 total_rank++;
1142 }
1143 }
1144}
1145
1146static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1147{
Martin Roth468d02c2019-10-23 21:44:42 -06001148 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001149 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1150 unsigned int channel_0_non_interleaved;
1151
1152 FOR_ALL_RANKS {
1153 if (info->populated_ranks[channel][slot][rank]) {
1154 total_mb[channel] +=
1155 pre_jedec ? 256 : (256 << info->
1156 density[channel][slot] >> info->
1157 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001158 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1159 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1160 (info->is_x16_module[channel][slot] |
1161 ((info->density[channel][slot] + 1) << 1))) |
1162 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001163 }
Felix Held04be2dd2018-07-29 04:53:22 +02001164 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1165 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001166 }
1167
1168 info->total_memory_mb = total_mb[0] + total_mb[1];
1169
1170 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001171 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 info->non_interleaved_part_mb =
1173 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1174 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001175 MCHBAR32(0x100) = channel_0_non_interleaved |
1176 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001177 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001178 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001179}
1180
1181static void program_board_delay(struct raminfo *info)
1182{
1183 int cas_latency_shift;
1184 int some_delay_ns;
1185 int some_delay_3_half_cycles;
1186
Martin Roth468d02c2019-10-23 21:44:42 -06001187 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001188 int high_multiplier;
1189 int lane_3_delay;
1190 int cas_latency_derived;
1191
1192 high_multiplier = 0;
1193 some_delay_ns = 200;
1194 some_delay_3_half_cycles = 4;
1195 cas_latency_shift = info->silicon_revision == 0
1196 || info->silicon_revision == 1 ? 1 : 0;
1197 if (info->revision < 8) {
1198 some_delay_ns = 600;
1199 cas_latency_shift = 0;
1200 }
1201 {
1202 int speed_bit;
1203 speed_bit =
1204 ((info->clock_speed_index > 1
1205 || (info->silicon_revision != 2
1206 && info->silicon_revision != 3))) ^ (info->revision >=
1207 0x10);
1208 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1209 3, 1);
1210 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1211 3, 1);
1212 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1213 && (info->silicon_revision == 2
1214 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001215 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001216 }
Felix Held04be2dd2018-07-29 04:53:22 +02001217 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1218 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001219
Felix Held04be2dd2018-07-29 04:53:22 +02001220 MCHBAR8(0x124) = info->board_lane_delay[4] +
1221 ((frequency_01(info) + 999) / 1000);
1222 MCHBAR16(0x125) = 0x1360;
1223 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001224 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001225 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001226 high_multiplier = 1;
1227 some_delay_2_half_cycles = ps_to_halfcycles(info,
1228 ((3 *
1229 fsbcycle_ps(info))
1230 >> 1) +
1231 (halfcycle_ps(info)
1232 *
1233 reg178_min[info->
1234 clock_speed_index]
1235 >> 6)
1236 +
1237 4 *
1238 halfcycle_ps(info)
1239 + 2230);
1240 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001241 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001242 (frequency_11(info) * 2) * (28 -
1243 some_delay_2_half_cycles) /
1244 (frequency_11(info) * 2 -
1245 4 * (info->fsb_frequency))) >> 3, 7);
1246 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001247 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001248 some_delay_3_half_cycles = 3;
1249 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001250 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1251 MCHBAR32(0x224 + (channel << 10)) =
1252 (info->max_slots_used_in_channel - 1) |
1253 ((info->cas_latency - 5 - info->clock_speed_index)
1254 << 21) | ((info->max_slots_used_in_channel +
1255 info->cas_latency - cas_latency_shift - 4) << 16) |
1256 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1257 ((info->cas_latency - info->clock_speed_index +
1258 info->max_slots_used_in_channel - 6) << 8);
1259 MCHBAR32(0x228 + (channel << 10)) =
1260 info->max_slots_used_in_channel;
1261 MCHBAR8(0x239 + (channel << 10)) = 32;
1262 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1263 (some_delay_3_half_cycles << 25) | 0x840000;
1264 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1265 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1266 MCHBAR32(0x24c + (channel << 10)) =
1267 ((!!info->clock_speed_index) << 17) |
1268 (((2 + info->clock_speed_index -
1269 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001270
Felix Held04be2dd2018-07-29 04:53:22 +02001271 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1272 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1273 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274
1275 write_500(info, channel,
1276 ((!info->populated_ranks[channel][1][1])
1277 | (!info->populated_ranks[channel][1][0] << 1)
1278 | (!info->populated_ranks[channel][0][1] << 2)
1279 | (!info->populated_ranks[channel][0][0] << 3)),
1280 0x4c9, 4, 1);
1281 }
1282
Felix Held22ca8cb2018-07-29 05:09:44 +02001283 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001284 {
1285 u8 freq_divisor = 2;
1286 if (info->fsb_frequency == frequency_11(info))
1287 freq_divisor = 3;
1288 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1289 freq_divisor = 1;
1290 else
1291 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001292 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001293 }
1294
1295 if (info->board_lane_delay[3] <= 10) {
1296 if (info->board_lane_delay[3] <= 8)
1297 lane_3_delay = info->board_lane_delay[3];
1298 else
1299 lane_3_delay = 10;
1300 } else {
1301 lane_3_delay = 12;
1302 }
1303 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1304 if (info->clock_speed_index > 1)
1305 cas_latency_derived++;
1306 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001307 MCHBAR32(0x240 + (channel << 10)) =
1308 ((info->clock_speed_index == 0) * 0x11000) |
1309 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1310 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001311 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1312 0x609, 6, 1);
1313 write_500(info, channel,
1314 info->clock_speed_index + 2 * info->cas_latency - 7,
1315 0x601, 6, 1);
1316
Felix Held04be2dd2018-07-29 04:53:22 +02001317 MCHBAR32(0x250 + (channel << 10)) =
1318 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1319 (info->board_lane_delay[7] << 2) |
1320 (info->board_lane_delay[4] << 16) |
1321 (info->board_lane_delay[1] << 25) |
1322 (info->board_lane_delay[1] << 29) | 1;
1323 MCHBAR32(0x254 + (channel << 10)) =
1324 (info->board_lane_delay[1] >> 3) |
1325 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1326 0x80 | (info->board_lane_delay[6] << 1) |
1327 (info->board_lane_delay[2] << 28) |
1328 (cas_latency_derived << 16) | 0x4700000;
1329 MCHBAR32(0x258 + (channel << 10)) =
1330 ((info->board_lane_delay[5] + info->clock_speed_index +
1331 9) << 12) | ((info->clock_speed_index -
1332 info->cas_latency + 12) << 8) |
1333 (info->board_lane_delay[2] << 17) |
1334 (info->board_lane_delay[4] << 24) | 0x47;
1335 MCHBAR32(0x25c + (channel << 10)) =
1336 (info->board_lane_delay[1] << 1) |
1337 (info->board_lane_delay[0] << 8) | 0x1da50000;
1338 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1339 MCHBAR8(0x5f8 + (channel << 10)) =
1340 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341 }
1342
1343 program_modules_memory_map(info, 1);
1344
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001345 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001346 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1347 MCHBAR16_OR(0x612, 0x100);
1348 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001349 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001350 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001352 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 }
1354}
1355
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001356#define DEFAULT_PCI_MMIO_SIZE 2048
1357#define HOST_BRIDGE PCI_DEVFN(0, 0)
1358
1359static unsigned int get_mmio_size(void)
1360{
1361 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001362 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001363
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001364 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001365 if (dev)
1366 cfg = dev->chip_info;
1367
1368 /* If this is zero, it just means devicetree.cb didn't set it */
1369 if (!cfg || cfg->pci_mmio_size == 0)
1370 return DEFAULT_PCI_MMIO_SIZE;
1371 else
1372 return cfg->pci_mmio_size;
1373}
1374
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001375static void program_total_memory_map(struct raminfo *info)
1376{
Angel Pons9333b742020-07-22 16:04:15 +02001377 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001379 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001380 unsigned int uma_base_igd;
1381 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001382 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001383 int memory_remap;
1384 unsigned int memory_map[8];
1385 int i;
1386 unsigned int current_limit;
1387 unsigned int tseg_base;
1388 int uma_size_igd = 0, uma_size_gtt = 0;
1389
1390 memset(memory_map, 0, sizeof(memory_map));
1391
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001392 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001393 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001394 gav(t);
1395 const int uma_sizes_gtt[16] =
1396 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1397 /* Igd memory */
1398 const int uma_sizes_igd[16] = {
1399 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1400 256, 512
1401 };
1402
1403 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1404 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1405 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001407 mmio_size = get_mmio_size();
1408
Angel Pons9333b742020-07-22 16:04:15 +02001409 tom = info->total_memory_mb;
1410 if (tom == 4096)
1411 tom = 4032;
1412 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1413 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1414 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001416 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001417 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001418 remap_base = MAX(4096, touud);
1419 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001420 }
Angel Pons9333b742020-07-22 16:04:15 +02001421 if (touud > 4096)
1422 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 quickpath_reserved = 0;
1424
Angel Pons3ab19b32020-07-22 16:29:54 +02001425 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426
Jacob Garber975a7e32019-06-10 16:32:47 -06001427 gav(t);
1428
1429 if (t & 0x800) {
1430 u32 shift = t >> 20;
1431 if (shift == 0)
1432 die("Quickpath value is 0\n");
1433 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001434 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001435
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001437 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438
Angel Pons9333b742020-07-22 16:04:15 +02001439 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 uma_base_gtt = uma_base_igd - uma_size_gtt;
1441 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1442 if (!memory_remap)
1443 tseg_base -= quickpath_reserved;
1444 tseg_base = ALIGN_DOWN(tseg_base, 8);
1445
Angel Pons16fe1e02020-07-22 16:12:33 +02001446 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1447 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001449 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1450 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001452 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001453
1454 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001455 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1456 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459
1460 current_limit = 0;
1461 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1462 memory_map[1] = 4096;
1463 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001464 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001465 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1467 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001468 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 }
1470}
1471
1472static void collect_system_info(struct raminfo *info)
1473{
1474 u32 capid0[3];
1475 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001476 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477
Angel Ponsb600d412021-01-16 16:33:48 +01001478 for (i = 0; i < 3; i++) {
1479 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1480 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1481 }
1482 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1483 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1484 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1485
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001486 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1487
1488 if ((capid0[1] >> 11) & 1)
1489 info->uma_enabled = 0;
1490 else
1491 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001492 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001493 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1494 info->silicon_revision = 0;
1495
1496 if (capid0[2] & 2) {
1497 info->silicon_revision = 0;
1498 info->max_supported_clock_speed_index = 2;
1499 for (channel = 0; channel < NUM_CHANNELS; channel++)
1500 if (info->populated_ranks[channel][0][0]
1501 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1502 3) {
1503 info->silicon_revision = 2;
1504 info->max_supported_clock_speed_index = 1;
1505 }
1506 } else {
1507 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1508 case 1:
1509 case 2:
1510 info->silicon_revision = 3;
1511 break;
1512 case 3:
1513 info->silicon_revision = 0;
1514 break;
1515 case 0:
1516 info->silicon_revision = 2;
1517 break;
1518 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001519 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001520 case 0x40:
1521 info->silicon_revision = 0;
1522 break;
1523 case 0x48:
1524 info->silicon_revision = 1;
1525 break;
1526 }
1527 }
1528}
1529
1530static void write_training_data(struct raminfo *info)
1531{
1532 int tm, channel, slot, rank, lane;
1533 if (info->revision < 8)
1534 return;
1535
1536 for (tm = 0; tm < 4; tm++)
1537 for (channel = 0; channel < NUM_CHANNELS; channel++)
1538 for (slot = 0; slot < NUM_SLOTS; slot++)
1539 for (rank = 0; rank < NUM_RANKS; rank++)
1540 for (lane = 0; lane < 9; lane++)
1541 write_500(info, channel,
1542 info->
1543 cached_training->
1544 lane_timings[tm]
1545 [channel][slot][rank]
1546 [lane],
1547 get_timing_register_addr
1548 (lane, tm, slot,
1549 rank), 9, 0);
1550 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1551 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1552}
1553
1554static void dump_timings(struct raminfo *info)
1555{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001556 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001557 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001558 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001559 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001560 slot, rank);
1561 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001562 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001563 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001564 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001565 read_500(info, channel,
1566 get_timing_register_addr
1567 (lane, i, slot, rank),
1568 9),
1569 info->training.
1570 lane_timings[i][channel][slot][rank]
1571 [lane]);
1572 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 }
1575 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001576 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001578 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580}
1581
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001582/* Read timings and other registers that need to be restored verbatim and
1583 put them to CBMEM.
1584 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585static void save_timings(struct raminfo *info)
1586{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001587 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 int channel, slot, rank, lane, i;
1589
1590 train = info->training;
1591 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1592 for (i = 0; i < 4; i++)
1593 train.lane_timings[i][channel][slot][rank][lane] =
1594 read_500(info, channel,
1595 get_timing_register_addr(lane, i, slot,
1596 rank), 9);
1597 train.reg_178 = read_1d0(0x178, 7);
1598 train.reg_10b = read_1d0(0x10b, 6);
1599
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001600 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1601 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001602 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001603 train.reg274265[channel][0] = reg32 >> 16;
1604 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001605 train.reg274265[channel][2] =
1606 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001607 }
Felix Held04be2dd2018-07-29 04:53:22 +02001608 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1609 train.reg_6dc = MCHBAR32(0x6dc);
1610 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001611
Arthur Heymansb3282092019-04-14 17:53:28 +02001612 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1613 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001614
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001616 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1617 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001618}
1619
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620static const struct ram_training *get_cached_training(void)
1621{
Shelley Chenad9cd682020-07-23 16:10:52 -07001622 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1623 MRC_CACHE_VERSION,
1624 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001625}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626
1627/* FIXME: add timeout. */
1628static void wait_heci_ready(void)
1629{
Felix Held04be2dd2018-07-29 04:53:22 +02001630 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1631 ;
Angel Ponseb537932020-09-14 19:18:11 +02001632
1633 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634}
1635
1636/* FIXME: add timeout. */
1637static void wait_heci_cb_avail(int len)
1638{
1639 union {
1640 struct mei_csr csr;
1641 u32 raw;
1642 } csr;
1643
Felix Held22ca8cb2018-07-29 05:09:44 +02001644 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1645 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646
Angel Ponseb537932020-09-14 19:18:11 +02001647 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001648 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001649 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1650 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651}
1652
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001653static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001654{
1655 int len = (head->length + 3) / 4;
1656 int i;
1657
1658 wait_heci_cb_avail(len + 1);
1659
1660 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001661 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001662 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001663 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001665 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1666 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667}
1668
Angel Ponseb537932020-09-14 19:18:11 +02001669static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670{
1671 struct mei_header head;
1672 int maxlen;
1673
1674 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001675 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676
1677 while (len) {
1678 int cur = len;
1679 if (cur > maxlen) {
1680 cur = maxlen;
1681 head.is_complete = 0;
1682 } else
1683 head.is_complete = 1;
1684 head.length = cur;
1685 head.reserved = 0;
1686 head.client_address = clientaddress;
1687 head.host_address = hostaddress;
1688 send_heci_packet(&head, (u32 *) msg);
1689 len -= cur;
1690 msg += cur;
1691 }
1692}
1693
1694/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001695static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696{
1697 union {
1698 struct mei_csr csr;
1699 u32 raw;
1700 } csr;
1701 int i = 0;
1702
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001703 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001705 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001706 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1707
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001708 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001710 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001711 *packet_size = 0;
1712 return 0;
1713 }
Angel Ponseb537932020-09-14 19:18:11 +02001714 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001715 *packet_size = 0;
1716 return -1;
1717 }
1718
Angel Ponseb537932020-09-14 19:18:11 +02001719 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001720 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001721 } while (((head->length + 3) >> 2) >
1722 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001723
1724 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001725 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726 *packet_size = head->length;
1727 if (!csr.csr.ready)
1728 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 return 0;
1731}
1732
1733/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001734static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735{
1736 struct mei_header head;
1737 int current_position;
1738
1739 current_position = 0;
1740 while (1) {
1741 u32 current_size;
1742 current_size = *message_size - current_position;
1743 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001744 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001745 &current_size) == -1)
1746 break;
1747 if (!current_size)
1748 break;
1749 current_position += current_size;
1750 if (head.is_complete) {
1751 *message_size = current_position;
1752 return 0;
1753 }
1754
1755 if (current_position >= *message_size)
1756 break;
1757 }
1758 *message_size = 0;
1759 return -1;
1760}
1761
Angel Pons55f11e22020-09-14 19:06:53 +02001762static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001763{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001764 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001765 u8 group_id;
1766 u8 command;
1767 u8 reserved;
1768 u8 result;
1769 u8 field2;
1770 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001771 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001772
1773 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1774 reply.command = 0;
1775
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001776 struct uma_message {
1777 u8 group_id;
1778 u8 cmd;
1779 u8 reserved;
1780 u8 result;
1781 u32 c2;
1782 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001783 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001784 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001785 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001786 .group_id = 0,
1787 .cmd = MKHI_SET_UMA,
1788 .reserved = 0,
1789 .result = 0,
1790 .c2 = 0x82,
1791 .heci_uma_addr = heci_uma_addr,
1792 .heci_uma_size = heci_uma_size,
1793 .c3 = 0,
1794 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001795 u32 reply_size;
1796
Angel Ponseb537932020-09-14 19:18:11 +02001797 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001798
1799 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001800 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001801 return;
1802
1803 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1804 die("HECI init failed\n");
1805}
1806
1807static void setup_heci_uma(struct raminfo *info)
1808{
Angel Pons298d34d2020-09-14 18:58:53 +02001809 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001810 return;
1811
Angel Pons36592bf2020-09-14 18:52:44 +02001812 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001813 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001814 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001815 info->memory_reserved_for_heci_mb)) << 20;
1816
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001817 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001818 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001819 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001820 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001821 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001822 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001823 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001824 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001825 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001826 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827
Angel Ponsee7fb342021-01-28 14:11:55 +01001828 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001829 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001830
Angel Ponsee7fb342021-01-28 14:11:55 +01001831 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001832 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833 }
1834
Felix Held04be2dd2018-07-29 04:53:22 +02001835 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836
Angel Pons55f11e22020-09-14 19:06:53 +02001837 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001839 pci_write_config32(HECIDEV, 0x10, 0x0);
1840 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841}
1842
1843static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1844{
1845 int ranks_in_channel;
1846 ranks_in_channel = info->populated_ranks[channel][0][0]
1847 + info->populated_ranks[channel][0][1]
1848 + info->populated_ranks[channel][1][0]
1849 + info->populated_ranks[channel][1][1];
1850
1851 /* empty channel */
1852 if (ranks_in_channel == 0)
1853 return 1;
1854
1855 if (ranks_in_channel != ranks)
1856 return 0;
1857 /* single slot */
1858 if (info->populated_ranks[channel][0][0] !=
1859 info->populated_ranks[channel][1][0])
1860 return 1;
1861 if (info->populated_ranks[channel][0][1] !=
1862 info->populated_ranks[channel][1][1])
1863 return 1;
1864 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1865 return 0;
1866 if (info->density[channel][0] != info->density[channel][1])
1867 return 0;
1868 return 1;
1869}
1870
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871static void read_4090(struct raminfo *info)
1872{
1873 int i, channel, slot, rank, lane;
1874 for (i = 0; i < 2; i++)
1875 for (slot = 0; slot < NUM_SLOTS; slot++)
1876 for (rank = 0; rank < NUM_RANKS; rank++)
1877 for (lane = 0; lane < 9; lane++)
1878 info->training.
1879 lane_timings[0][i][slot][rank][lane]
1880 = 32;
1881
1882 for (i = 1; i < 4; i++)
1883 for (channel = 0; channel < NUM_CHANNELS; channel++)
1884 for (slot = 0; slot < NUM_SLOTS; slot++)
1885 for (rank = 0; rank < NUM_RANKS; rank++)
1886 for (lane = 0; lane < 9; lane++) {
1887 info->training.
1888 lane_timings[i][channel]
1889 [slot][rank][lane] =
1890 read_500(info, channel,
1891 get_timing_register_addr
1892 (lane, i, slot,
1893 rank), 9)
1894 + (i == 1) * 11; // !!!!
1895 }
1896
1897}
1898
1899static u32 get_etalon2(int flip, u32 addr)
1900{
1901 const u16 invmask[] = {
1902 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1903 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1904 };
1905 u32 ret;
1906 u32 comp4 = addr / 480;
1907 addr %= 480;
1908 u32 comp1 = addr & 0xf;
1909 u32 comp2 = (addr >> 4) & 1;
1910 u32 comp3 = addr >> 5;
1911
1912 if (comp4)
1913 ret = 0x1010101 << (comp4 - 1);
1914 else
1915 ret = 0;
1916 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1917 ret = ~ret;
1918
1919 return ret;
1920}
1921
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001922static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001923{
1924 msr_t msr = {.lo = 0, .hi = 0 };
1925
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001926 wrmsr(MTRR_PHYS_BASE(3), msr);
1927 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001928}
1929
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001930static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001931{
1932 msr_t msr;
1933 msr.lo = base | MTRR_TYPE_WRPROT;
1934 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001935 wrmsr(MTRR_PHYS_BASE(3), msr);
1936 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001937 & 0xffffffff);
1938 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001939 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001940}
1941
1942static void flush_cache(u32 start, u32 size)
1943{
1944 u32 end;
1945 u32 addr;
1946
1947 end = start + (ALIGN_DOWN(size + 4096, 4096));
1948 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001949 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001950}
1951
1952static void clear_errors(void)
1953{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001954 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001955}
1956
1957static void write_testing(struct raminfo *info, int totalrank, int flip)
1958{
1959 int nwrites = 0;
1960 /* in 8-byte units. */
1961 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001962 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001963
Patrick Rudolph819c2062019-11-29 19:27:37 +01001964 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001965 for (offset = 0; offset < 9 * 480; offset += 2) {
1966 write32(base + offset * 8, get_etalon2(flip, offset));
1967 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1968 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1969 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1970 nwrites += 4;
1971 if (nwrites >= 320) {
1972 clear_errors();
1973 nwrites = 0;
1974 }
1975 }
1976}
1977
1978static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1979{
1980 u8 failmask = 0;
1981 int i;
1982 int comp1, comp2, comp3;
1983 u32 failxor[2] = { 0, 0 };
1984
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001985 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001986
1987 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1988 for (comp1 = 0; comp1 < 4; comp1++)
1989 for (comp2 = 0; comp2 < 60; comp2++) {
1990 u32 re[4];
1991 u32 curroffset =
1992 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1993 read128((total_rank << 28) | (curroffset << 3),
1994 (u64 *) re);
1995 failxor[0] |=
1996 get_etalon2(flip, curroffset) ^ re[0];
1997 failxor[1] |=
1998 get_etalon2(flip, curroffset) ^ re[1];
1999 failxor[0] |=
2000 get_etalon2(flip, curroffset | 1) ^ re[2];
2001 failxor[1] |=
2002 get_etalon2(flip, curroffset | 1) ^ re[3];
2003 }
2004 for (i = 0; i < 8; i++)
2005 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2006 failmask |= 1 << i;
2007 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002008 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002009 flush_cache((total_rank << 28), 1728 * 5 * 4);
2010 return failmask;
2011}
2012
2013const u32 seed1[0x18] = {
2014 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2015 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2016 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2017 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2018 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2019 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2020};
2021
2022static u32 get_seed2(int a, int b)
2023{
2024 const u32 seed2[5] = {
2025 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2026 0x5b6db6db,
2027 };
2028 u32 r;
2029 r = seed2[(a + (a >= 10)) / 5];
2030 return b ? ~r : r;
2031}
2032
2033static int make_shift(int comp2, int comp5, int x)
2034{
2035 const u8 seed3[32] = {
2036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2037 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2038 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2039 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2040 };
2041
2042 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2043}
2044
2045static u32 get_etalon(int flip, u32 addr)
2046{
2047 u32 mask_byte = 0;
2048 int comp1 = (addr >> 1) & 1;
2049 int comp2 = (addr >> 3) & 0x1f;
2050 int comp3 = (addr >> 8) & 0xf;
2051 int comp4 = (addr >> 12) & 0xf;
2052 int comp5 = (addr >> 16) & 0x1f;
2053 u32 mask_bit = ~(0x10001 << comp3);
2054 u32 part1;
2055 u32 part2;
2056 int byte;
2057
2058 part2 =
2059 ((seed1[comp5] >>
2060 make_shift(comp2, comp5,
2061 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2062 part1 =
2063 ((seed1[comp5] >>
2064 make_shift(comp2, comp5,
2065 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2066
2067 for (byte = 0; byte < 4; byte++)
2068 if ((get_seed2(comp5, comp4) >>
2069 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2070 mask_byte |= 0xff << (8 * byte);
2071
2072 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2073 (comp3 + 16));
2074}
2075
2076static void
2077write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2078 char flip)
2079{
2080 int i;
2081 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002082 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2083 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002084}
2085
2086static u8
2087check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2088 char flip)
2089{
2090 u8 failmask = 0;
2091 u32 failxor[2];
2092 int i;
2093 int comp1, comp2, comp3;
2094
2095 failxor[0] = 0;
2096 failxor[1] = 0;
2097
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002098 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002099 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2100 for (comp1 = 0; comp1 < 16; comp1++)
2101 for (comp2 = 0; comp2 < 64; comp2++) {
2102 u32 addr =
2103 (totalrank << 28) | (region << 25) | (block
2104 << 16)
2105 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2106 2);
2107 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002108 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002109 }
2110 for (i = 0; i < 8; i++)
2111 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2112 failmask |= 1 << i;
2113 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002114 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002115 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2116 return failmask;
2117}
2118
2119static int check_bounded(unsigned short *vals, u16 bound)
2120{
2121 int i;
2122
2123 for (i = 0; i < 8; i++)
2124 if (vals[i] < bound)
2125 return 0;
2126 return 1;
2127}
2128
2129enum state {
2130 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2131};
2132
2133static int validate_state(enum state *in)
2134{
2135 int i;
2136 for (i = 0; i < 8; i++)
2137 if (in[i] != COMPLETE)
2138 return 0;
2139 return 1;
2140}
2141
2142static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002143do_fsm(enum state *state, u16 *counter,
2144 u8 fail_mask, int margin, int uplimit,
2145 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002146{
2147 int lane;
2148
2149 for (lane = 0; lane < 8; lane++) {
2150 int is_fail = (fail_mask >> lane) & 1;
2151 switch (state[lane]) {
2152 case BEFORE_USABLE:
2153 if (!is_fail) {
2154 counter[lane] = 1;
2155 state[lane] = AT_USABLE;
2156 break;
2157 }
2158 counter[lane] = 0;
2159 state[lane] = BEFORE_USABLE;
2160 break;
2161 case AT_USABLE:
2162 if (!is_fail) {
2163 ++counter[lane];
2164 if (counter[lane] >= margin) {
2165 state[lane] = AT_MARGIN;
2166 res_low[lane] = val - margin + 1;
2167 break;
2168 }
2169 state[lane] = 1;
2170 break;
2171 }
2172 counter[lane] = 0;
2173 state[lane] = BEFORE_USABLE;
2174 break;
2175 case AT_MARGIN:
2176 if (is_fail) {
2177 state[lane] = COMPLETE;
2178 res_high[lane] = val - 1;
2179 } else {
2180 counter[lane]++;
2181 state[lane] = AT_MARGIN;
2182 if (val == uplimit) {
2183 state[lane] = COMPLETE;
2184 res_high[lane] = uplimit;
2185 }
2186 }
2187 break;
2188 case COMPLETE:
2189 break;
2190 }
2191 }
2192}
2193
2194static void
2195train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2196 u8 total_rank, u8 reg_178, int first_run, int niter,
2197 timing_bounds_t * timings)
2198{
2199 int lane;
2200 enum state state[8];
2201 u16 count[8];
2202 u8 lower_usable[8];
2203 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002204 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002205 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002206 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002207
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002208 for (i = 0; i < 8; i++)
2209 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002210
2211 if (!first_run) {
2212 int is_all_ok = 1;
2213 for (lane = 0; lane < 8; lane++)
2214 if (timings[reg_178][channel][slot][rank][lane].
2215 smallest ==
2216 timings[reg_178][channel][slot][rank][lane].
2217 largest) {
2218 timings[reg_178][channel][slot][rank][lane].
2219 smallest = 0;
2220 timings[reg_178][channel][slot][rank][lane].
2221 largest = 0;
2222 is_all_ok = 0;
2223 }
2224 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002225 for (i = 0; i < 8; i++)
2226 state[i] = COMPLETE;
2227 }
2228 }
2229
2230 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2231 u8 failmask = 0;
2232 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2233 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2234 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002235 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002236 do_fsm(state, count, failmask, 5, 47, lower_usable,
2237 upper_usable, reg1b3);
2238 }
2239
2240 if (reg1b3) {
2241 write_1d0(0, 0x1b3, 6, 1);
2242 write_1d0(0, 0x1a3, 6, 1);
2243 for (lane = 0; lane < 8; lane++) {
2244 if (state[lane] == COMPLETE) {
2245 timings[reg_178][channel][slot][rank][lane].
2246 smallest =
2247 lower_usable[lane] +
2248 (info->training.
2249 lane_timings[0][channel][slot][rank][lane]
2250 & 0x3F) - 32;
2251 timings[reg_178][channel][slot][rank][lane].
2252 largest =
2253 upper_usable[lane] +
2254 (info->training.
2255 lane_timings[0][channel][slot][rank][lane]
2256 & 0x3F) - 32;
2257 }
2258 }
2259 }
2260
2261 if (!first_run) {
2262 for (lane = 0; lane < 8; lane++)
2263 if (state[lane] == COMPLETE) {
2264 write_500(info, channel,
2265 timings[reg_178][channel][slot][rank]
2266 [lane].smallest,
2267 get_timing_register_addr(lane, 0,
2268 slot, rank),
2269 9, 1);
2270 write_500(info, channel,
2271 timings[reg_178][channel][slot][rank]
2272 [lane].smallest +
2273 info->training.
2274 lane_timings[1][channel][slot][rank]
2275 [lane]
2276 -
2277 info->training.
2278 lane_timings[0][channel][slot][rank]
2279 [lane], get_timing_register_addr(lane,
2280 1,
2281 slot,
2282 rank),
2283 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002284 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002285 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002286 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002287
2288 do {
2289 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002290 for (i = 0; i < niter; i++) {
2291 if (failmask == 0xFF)
2292 break;
2293 failmask |=
2294 check_testing_type2(info, total_rank, 2, i,
2295 0);
2296 failmask |=
2297 check_testing_type2(info, total_rank, 3, i,
2298 1);
2299 }
Felix Held04be2dd2018-07-29 04:53:22 +02002300 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002301 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002302 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002303 if ((1 << lane) & failmask) {
2304 if (timings[reg_178][channel]
2305 [slot][rank][lane].
2306 largest <=
2307 timings[reg_178][channel]
2308 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002309 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002310 [lane] = -1;
2311 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002312 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002313 [lane] = 0;
2314 timings[reg_178]
2315 [channel][slot]
2316 [rank][lane].
2317 smallest++;
2318 write_500(info, channel,
2319 timings
2320 [reg_178]
2321 [channel]
2322 [slot][rank]
2323 [lane].
2324 smallest,
2325 get_timing_register_addr
2326 (lane, 0,
2327 slot, rank),
2328 9, 1);
2329 write_500(info, channel,
2330 timings
2331 [reg_178]
2332 [channel]
2333 [slot][rank]
2334 [lane].
2335 smallest +
2336 info->
2337 training.
2338 lane_timings
2339 [1][channel]
2340 [slot][rank]
2341 [lane]
2342 -
2343 info->
2344 training.
2345 lane_timings
2346 [0][channel]
2347 [slot][rank]
2348 [lane],
2349 get_timing_register_addr
2350 (lane, 1,
2351 slot, rank),
2352 9, 1);
2353 }
2354 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002355 num_successfully_checked[lane]
2356 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002357 }
2358 }
Felix Held04be2dd2018-07-29 04:53:22 +02002359 while (!check_bounded(num_successfully_checked, 2))
2360 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002361
2362 for (lane = 0; lane < 8; lane++)
2363 if (state[lane] == COMPLETE) {
2364 write_500(info, channel,
2365 timings[reg_178][channel][slot][rank]
2366 [lane].largest,
2367 get_timing_register_addr(lane, 0,
2368 slot, rank),
2369 9, 1);
2370 write_500(info, channel,
2371 timings[reg_178][channel][slot][rank]
2372 [lane].largest +
2373 info->training.
2374 lane_timings[1][channel][slot][rank]
2375 [lane]
2376 -
2377 info->training.
2378 lane_timings[0][channel][slot][rank]
2379 [lane], get_timing_register_addr(lane,
2380 1,
2381 slot,
2382 rank),
2383 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002384 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002385 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002386 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002387
2388 do {
2389 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002390 for (i = 0; i < niter; i++) {
2391 if (failmask == 0xFF)
2392 break;
2393 failmask |=
2394 check_testing_type2(info, total_rank, 2, i,
2395 0);
2396 failmask |=
2397 check_testing_type2(info, total_rank, 3, i,
2398 1);
2399 }
2400
Felix Held04be2dd2018-07-29 04:53:22 +02002401 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002402 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002403 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002404 if ((1 << lane) & failmask) {
2405 if (timings[reg_178][channel]
2406 [slot][rank][lane].
2407 largest <=
2408 timings[reg_178][channel]
2409 [slot][rank][lane].
2410 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002411 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002412 [lane] = -1;
2413 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002414 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002415 [lane] = 0;
2416 timings[reg_178]
2417 [channel][slot]
2418 [rank][lane].
2419 largest--;
2420 write_500(info, channel,
2421 timings
2422 [reg_178]
2423 [channel]
2424 [slot][rank]
2425 [lane].
2426 largest,
2427 get_timing_register_addr
2428 (lane, 0,
2429 slot, rank),
2430 9, 1);
2431 write_500(info, channel,
2432 timings
2433 [reg_178]
2434 [channel]
2435 [slot][rank]
2436 [lane].
2437 largest +
2438 info->
2439 training.
2440 lane_timings
2441 [1][channel]
2442 [slot][rank]
2443 [lane]
2444 -
2445 info->
2446 training.
2447 lane_timings
2448 [0][channel]
2449 [slot][rank]
2450 [lane],
2451 get_timing_register_addr
2452 (lane, 1,
2453 slot, rank),
2454 9, 1);
2455 }
2456 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002457 num_successfully_checked[lane]
2458 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002459 }
2460 }
2461 }
Felix Held04be2dd2018-07-29 04:53:22 +02002462 while (!check_bounded(num_successfully_checked, 3))
2463 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002464
2465 for (lane = 0; lane < 8; lane++) {
2466 write_500(info, channel,
2467 info->training.
2468 lane_timings[0][channel][slot][rank][lane],
2469 get_timing_register_addr(lane, 0, slot, rank),
2470 9, 1);
2471 write_500(info, channel,
2472 info->training.
2473 lane_timings[1][channel][slot][rank][lane],
2474 get_timing_register_addr(lane, 1, slot, rank),
2475 9, 1);
2476 if (timings[reg_178][channel][slot][rank][lane].
2477 largest <=
2478 timings[reg_178][channel][slot][rank][lane].
2479 smallest) {
2480 timings[reg_178][channel][slot][rank][lane].
2481 largest = 0;
2482 timings[reg_178][channel][slot][rank][lane].
2483 smallest = 0;
2484 }
2485 }
2486 }
2487}
2488
2489static void set_10b(struct raminfo *info, u8 val)
2490{
2491 int channel;
2492 int slot, rank;
2493 int lane;
2494
2495 if (read_1d0(0x10b, 6) == val)
2496 return;
2497
2498 write_1d0(val, 0x10b, 6, 1);
2499
2500 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2501 u16 reg_500;
2502 reg_500 = read_500(info, channel,
2503 get_timing_register_addr(lane, 0, slot,
2504 rank), 9);
2505 if (val == 1) {
2506 if (lut16[info->clock_speed_index] <= reg_500)
2507 reg_500 -= lut16[info->clock_speed_index];
2508 else
2509 reg_500 = 0;
2510 } else {
2511 reg_500 += lut16[info->clock_speed_index];
2512 }
2513 write_500(info, channel, reg_500,
2514 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2515 }
2516}
2517
2518static void set_ecc(int onoff)
2519{
2520 int channel;
2521 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2522 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002523 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002524 if (onoff)
2525 t |= 1;
2526 else
2527 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002528 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002529 }
2530}
2531
2532static void set_178(u8 val)
2533{
2534 if (val >= 31)
2535 val = val - 31;
2536 else
2537 val = 63 - val;
2538
2539 write_1d0(2 * val, 0x178, 7, 1);
2540}
2541
2542static void
2543write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2544 int type)
2545{
2546 int lane;
2547
2548 for (lane = 0; lane < 8; lane++)
2549 write_500(info, channel,
2550 info->training.
2551 lane_timings[type][channel][slot][rank][lane],
2552 get_timing_register_addr(lane, type, slot, rank), 9,
2553 0);
2554}
2555
2556static void
2557try_timing_offsets(struct raminfo *info, int channel,
2558 int slot, int rank, int totalrank)
2559{
2560 u16 count[8];
2561 enum state state[8];
2562 u8 lower_usable[8], upper_usable[8];
2563 int lane;
2564 int i;
2565 int flip = 1;
2566 int timing_offset;
2567
2568 for (i = 0; i < 8; i++)
2569 state[i] = BEFORE_USABLE;
2570
2571 memset(count, 0, sizeof(count));
2572
2573 for (lane = 0; lane < 8; lane++)
2574 write_500(info, channel,
2575 info->training.
2576 lane_timings[2][channel][slot][rank][lane] + 32,
2577 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2578
2579 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2580 timing_offset++) {
2581 u8 failmask;
2582 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2583 failmask = 0;
2584 for (i = 0; i < 2 && failmask != 0xff; i++) {
2585 flip = !flip;
2586 write_testing(info, totalrank, flip);
2587 failmask |= check_testing(info, totalrank, flip);
2588 }
2589 do_fsm(state, count, failmask, 10, 63, lower_usable,
2590 upper_usable, timing_offset);
2591 }
2592 write_1d0(0, 0x1bb, 6, 1);
2593 dump_timings(info);
2594 if (!validate_state(state))
2595 die("Couldn't discover DRAM timings (1)\n");
2596
2597 for (lane = 0; lane < 8; lane++) {
2598 u8 bias = 0;
2599
2600 if (info->silicon_revision) {
2601 int usable_length;
2602
2603 usable_length = upper_usable[lane] - lower_usable[lane];
2604 if (usable_length >= 20) {
2605 bias = usable_length / 2 - 10;
2606 if (bias >= 2)
2607 bias = 2;
2608 }
2609 }
2610 write_500(info, channel,
2611 info->training.
2612 lane_timings[2][channel][slot][rank][lane] +
2613 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2614 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2615 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2616 info->training.lane_timings[2][channel][slot][rank][lane] +
2617 lower_usable[lane];
2618 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2619 info->training.lane_timings[2][channel][slot][rank][lane] +
2620 upper_usable[lane];
2621 info->training.timing2_offset[channel][slot][rank][lane] =
2622 info->training.lane_timings[2][channel][slot][rank][lane];
2623 }
2624}
2625
2626static u8
2627choose_training(struct raminfo *info, int channel, int slot, int rank,
2628 int lane, timing_bounds_t * timings, u8 center_178)
2629{
2630 u16 central_weight;
2631 u16 side_weight;
2632 unsigned int sum = 0, count = 0;
2633 u8 span;
2634 u8 lower_margin, upper_margin;
2635 u8 reg_178;
2636 u8 result;
2637
2638 span = 12;
2639 central_weight = 20;
2640 side_weight = 20;
2641 if (info->silicon_revision == 1 && channel == 1) {
2642 central_weight = 5;
2643 side_weight = 20;
2644 if ((info->
2645 populated_ranks_mask[1] ^ (info->
2646 populated_ranks_mask[1] >> 2)) &
2647 1)
2648 span = 18;
2649 }
2650 if ((info->populated_ranks_mask[0] & 5) == 5) {
2651 central_weight = 20;
2652 side_weight = 20;
2653 }
2654 if (info->clock_speed_index >= 2
2655 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2656 if (info->silicon_revision == 1) {
2657 switch (channel) {
2658 case 0:
2659 if (lane == 1) {
2660 central_weight = 10;
2661 side_weight = 20;
2662 }
2663 break;
2664 case 1:
2665 if (lane == 6) {
2666 side_weight = 5;
2667 central_weight = 20;
2668 }
2669 break;
2670 }
2671 }
2672 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2673 side_weight = 5;
2674 central_weight = 20;
2675 }
2676 }
2677 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2678 reg_178 += span) {
2679 u8 smallest;
2680 u8 largest;
2681 largest = timings[reg_178][channel][slot][rank][lane].largest;
2682 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2683 if (largest - smallest + 1 >= 5) {
2684 unsigned int weight;
2685 if (reg_178 == center_178)
2686 weight = central_weight;
2687 else
2688 weight = side_weight;
2689 sum += weight * (largest + smallest);
2690 count += weight;
2691 }
2692 }
2693 dump_timings(info);
2694 if (count == 0)
2695 die("Couldn't discover DRAM timings (2)\n");
2696 result = sum / (2 * count);
2697 lower_margin =
2698 result - timings[center_178][channel][slot][rank][lane].smallest;
2699 upper_margin =
2700 timings[center_178][channel][slot][rank][lane].largest - result;
2701 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002702 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002703 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002704 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002705 return result;
2706}
2707
2708#define STANDARD_MIN_MARGIN 5
2709
2710static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2711{
2712 u16 margin[64];
2713 int lane, rank, slot, channel;
2714 u8 reg178;
2715 int count = 0, sum = 0;
2716
2717 for (reg178 = reg178_min[info->clock_speed_index];
2718 reg178 < reg178_max[info->clock_speed_index];
2719 reg178 += reg178_step[info->clock_speed_index]) {
2720 margin[reg178] = -1;
2721 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2722 int curmargin =
2723 timings[reg178][channel][slot][rank][lane].largest -
2724 timings[reg178][channel][slot][rank][lane].
2725 smallest + 1;
2726 if (curmargin < margin[reg178])
2727 margin[reg178] = curmargin;
2728 }
2729 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2730 u16 weight;
2731 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2732 sum += weight * reg178;
2733 count += weight;
2734 }
2735 }
2736 dump_timings(info);
2737 if (count == 0)
2738 die("Couldn't discover DRAM timings (3)\n");
2739
2740 u8 threshold;
2741
2742 for (threshold = 30; threshold >= 5; threshold--) {
2743 int usable_length = 0;
2744 int smallest_fount = 0;
2745 for (reg178 = reg178_min[info->clock_speed_index];
2746 reg178 < reg178_max[info->clock_speed_index];
2747 reg178 += reg178_step[info->clock_speed_index])
2748 if (margin[reg178] >= threshold) {
2749 usable_length +=
2750 reg178_step[info->clock_speed_index];
2751 info->training.reg178_largest =
2752 reg178 -
2753 2 * reg178_step[info->clock_speed_index];
2754
2755 if (!smallest_fount) {
2756 smallest_fount = 1;
2757 info->training.reg178_smallest =
2758 reg178 +
2759 reg178_step[info->
2760 clock_speed_index];
2761 }
2762 }
2763 if (usable_length >= 0x21)
2764 break;
2765 }
2766
2767 return sum / count;
2768}
2769
2770static int check_cached_sanity(struct raminfo *info)
2771{
2772 int lane;
2773 int slot, rank;
2774 int channel;
2775
2776 if (!info->cached_training)
2777 return 0;
2778
2779 for (channel = 0; channel < NUM_CHANNELS; channel++)
2780 for (slot = 0; slot < NUM_SLOTS; slot++)
2781 for (rank = 0; rank < NUM_RANKS; rank++)
2782 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2783 u16 cached_value, estimation_value;
2784 cached_value =
2785 info->cached_training->
2786 lane_timings[1][channel][slot][rank]
2787 [lane];
2788 if (cached_value >= 0x18
2789 && cached_value <= 0x1E7) {
2790 estimation_value =
2791 info->training.
2792 lane_timings[1][channel]
2793 [slot][rank][lane];
2794 if (estimation_value <
2795 cached_value - 24)
2796 return 0;
2797 if (estimation_value >
2798 cached_value + 24)
2799 return 0;
2800 }
2801 }
2802 return 1;
2803}
2804
2805static int try_cached_training(struct raminfo *info)
2806{
2807 u8 saved_243[2];
2808 u8 tm;
2809
2810 int channel, slot, rank, lane;
2811 int flip = 1;
2812 int i, j;
2813
2814 if (!check_cached_sanity(info))
2815 return 0;
2816
2817 info->training.reg178_center = info->cached_training->reg178_center;
2818 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2819 info->training.reg178_largest = info->cached_training->reg178_largest;
2820 memcpy(&info->training.timing_bounds,
2821 &info->cached_training->timing_bounds,
2822 sizeof(info->training.timing_bounds));
2823 memcpy(&info->training.timing_offset,
2824 &info->cached_training->timing_offset,
2825 sizeof(info->training.timing_offset));
2826
2827 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002828 saved_243[0] = MCHBAR8(0x243);
2829 saved_243[1] = MCHBAR8(0x643);
2830 MCHBAR8(0x243) = saved_243[0] | 2;
2831 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002832 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002833 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002834 if (read_1d0(0x10b, 6) & 1)
2835 set_10b(info, 0);
2836 for (tm = 0; tm < 2; tm++) {
2837 int totalrank;
2838
2839 set_178(tm ? info->cached_training->reg178_largest : info->
2840 cached_training->reg178_smallest);
2841
2842 totalrank = 0;
2843 /* Check timing ranges. With i == 0 we check smallest one and with
2844 i == 1 the largest bound. With j == 0 we check that on the bound
2845 it still works whereas with j == 1 we check that just outside of
2846 bound we fail.
2847 */
2848 FOR_POPULATED_RANKS_BACKWARDS {
2849 for (i = 0; i < 2; i++) {
2850 for (lane = 0; lane < 8; lane++) {
2851 write_500(info, channel,
2852 info->cached_training->
2853 timing2_bounds[channel][slot]
2854 [rank][lane][i],
2855 get_timing_register_addr(lane,
2856 3,
2857 slot,
2858 rank),
2859 9, 1);
2860
2861 if (!i)
2862 write_500(info, channel,
2863 info->
2864 cached_training->
2865 timing2_offset
2866 [channel][slot][rank]
2867 [lane],
2868 get_timing_register_addr
2869 (lane, 2, slot, rank),
2870 9, 1);
2871 write_500(info, channel,
2872 i ? info->cached_training->
2873 timing_bounds[tm][channel]
2874 [slot][rank][lane].
2875 largest : info->
2876 cached_training->
2877 timing_bounds[tm][channel]
2878 [slot][rank][lane].smallest,
2879 get_timing_register_addr(lane,
2880 0,
2881 slot,
2882 rank),
2883 9, 1);
2884 write_500(info, channel,
2885 info->cached_training->
2886 timing_offset[channel][slot]
2887 [rank][lane] +
2888 (i ? info->cached_training->
2889 timing_bounds[tm][channel]
2890 [slot][rank][lane].
2891 largest : info->
2892 cached_training->
2893 timing_bounds[tm][channel]
2894 [slot][rank][lane].
2895 smallest) - 64,
2896 get_timing_register_addr(lane,
2897 1,
2898 slot,
2899 rank),
2900 9, 1);
2901 }
2902 for (j = 0; j < 2; j++) {
2903 u8 failmask;
2904 u8 expected_failmask;
2905 char reg1b3;
2906
2907 reg1b3 = (j == 1) + 4;
2908 reg1b3 =
2909 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2910 write_1d0(reg1b3, 0x1bb, 6, 1);
2911 write_1d0(reg1b3, 0x1b3, 6, 1);
2912 write_1d0(reg1b3, 0x1a3, 6, 1);
2913
2914 flip = !flip;
2915 write_testing(info, totalrank, flip);
2916 failmask =
2917 check_testing(info, totalrank,
2918 flip);
2919 expected_failmask =
2920 j == 0 ? 0x00 : 0xff;
2921 if (failmask != expected_failmask)
2922 goto fail;
2923 }
2924 }
2925 totalrank++;
2926 }
2927 }
2928
2929 set_178(info->cached_training->reg178_center);
2930 if (info->use_ecc)
2931 set_ecc(1);
2932 write_training_data(info);
2933 write_1d0(0, 322, 3, 1);
2934 info->training = *info->cached_training;
2935
2936 write_1d0(0, 0x1bb, 6, 1);
2937 write_1d0(0, 0x1b3, 6, 1);
2938 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002939 MCHBAR8(0x243) = saved_243[0];
2940 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002941
2942 return 1;
2943
2944fail:
2945 FOR_POPULATED_RANKS {
2946 write_500_timings_type(info, channel, slot, rank, 1);
2947 write_500_timings_type(info, channel, slot, rank, 2);
2948 write_500_timings_type(info, channel, slot, rank, 3);
2949 }
2950
2951 write_1d0(0, 0x1bb, 6, 1);
2952 write_1d0(0, 0x1b3, 6, 1);
2953 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002954 MCHBAR8(0x243) = saved_243[0];
2955 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002956
2957 return 0;
2958}
2959
2960static void do_ram_training(struct raminfo *info)
2961{
2962 u8 saved_243[2];
2963 int totalrank = 0;
2964 u8 reg_178;
2965 int niter;
2966
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002967 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002968 int lane, rank, slot, channel;
2969 u8 reg178_center;
2970
2971 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002972 saved_243[0] = MCHBAR8(0x243);
2973 saved_243[1] = MCHBAR8(0x643);
2974 MCHBAR8(0x243) = saved_243[0] | 2;
2975 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002976 switch (info->clock_speed_index) {
2977 case 0:
2978 niter = 5;
2979 break;
2980 case 1:
2981 niter = 10;
2982 break;
2983 default:
2984 niter = 19;
2985 break;
2986 }
2987 set_ecc(0);
2988
2989 FOR_POPULATED_RANKS_BACKWARDS {
2990 int i;
2991
2992 write_500_timings_type(info, channel, slot, rank, 0);
2993
2994 write_testing(info, totalrank, 0);
2995 for (i = 0; i < niter; i++) {
2996 write_testing_type2(info, totalrank, 2, i, 0);
2997 write_testing_type2(info, totalrank, 3, i, 1);
2998 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002999 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003000 totalrank++;
3001 }
3002
3003 if (reg178_min[info->clock_speed_index] <
3004 reg178_max[info->clock_speed_index])
3005 memset(timings[reg178_min[info->clock_speed_index]], 0,
3006 sizeof(timings[0]) *
3007 (reg178_max[info->clock_speed_index] -
3008 reg178_min[info->clock_speed_index]));
3009 for (reg_178 = reg178_min[info->clock_speed_index];
3010 reg_178 < reg178_max[info->clock_speed_index];
3011 reg_178 += reg178_step[info->clock_speed_index]) {
3012 totalrank = 0;
3013 set_178(reg_178);
3014 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3015 for (slot = 0; slot < NUM_SLOTS; slot++)
3016 for (rank = 0; rank < NUM_RANKS; rank++) {
3017 memset(&timings[reg_178][channel][slot]
3018 [rank][0].smallest, 0, 16);
3019 if (info->
3020 populated_ranks[channel][slot]
3021 [rank]) {
3022 train_ram_at_178(info, channel,
3023 slot, rank,
3024 totalrank,
3025 reg_178, 1,
3026 niter,
3027 timings);
3028 totalrank++;
3029 }
3030 }
3031 }
3032
3033 reg178_center = choose_reg178(info, timings);
3034
3035 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3036 info->training.timing_bounds[0][channel][slot][rank][lane].
3037 smallest =
3038 timings[info->training.
3039 reg178_smallest][channel][slot][rank][lane].
3040 smallest;
3041 info->training.timing_bounds[0][channel][slot][rank][lane].
3042 largest =
3043 timings[info->training.
3044 reg178_smallest][channel][slot][rank][lane].largest;
3045 info->training.timing_bounds[1][channel][slot][rank][lane].
3046 smallest =
3047 timings[info->training.
3048 reg178_largest][channel][slot][rank][lane].smallest;
3049 info->training.timing_bounds[1][channel][slot][rank][lane].
3050 largest =
3051 timings[info->training.
3052 reg178_largest][channel][slot][rank][lane].largest;
3053 info->training.timing_offset[channel][slot][rank][lane] =
3054 info->training.lane_timings[1][channel][slot][rank][lane]
3055 -
3056 info->training.lane_timings[0][channel][slot][rank][lane] +
3057 64;
3058 }
3059
3060 if (info->silicon_revision == 1
3061 && (info->
3062 populated_ranks_mask[1] ^ (info->
3063 populated_ranks_mask[1] >> 2)) & 1) {
3064 int ranks_after_channel1;
3065
3066 totalrank = 0;
3067 for (reg_178 = reg178_center - 18;
3068 reg_178 <= reg178_center + 18; reg_178 += 18) {
3069 totalrank = 0;
3070 set_178(reg_178);
3071 for (slot = 0; slot < NUM_SLOTS; slot++)
3072 for (rank = 0; rank < NUM_RANKS; rank++) {
3073 if (info->
3074 populated_ranks[1][slot][rank]) {
3075 train_ram_at_178(info, 1, slot,
3076 rank,
3077 totalrank,
3078 reg_178, 0,
3079 niter,
3080 timings);
3081 totalrank++;
3082 }
3083 }
3084 }
3085 ranks_after_channel1 = totalrank;
3086
3087 for (reg_178 = reg178_center - 12;
3088 reg_178 <= reg178_center + 12; reg_178 += 12) {
3089 totalrank = ranks_after_channel1;
3090 set_178(reg_178);
3091 for (slot = 0; slot < NUM_SLOTS; slot++)
3092 for (rank = 0; rank < NUM_RANKS; rank++)
3093 if (info->
3094 populated_ranks[0][slot][rank]) {
3095 train_ram_at_178(info, 0, slot,
3096 rank,
3097 totalrank,
3098 reg_178, 0,
3099 niter,
3100 timings);
3101 totalrank++;
3102 }
3103
3104 }
3105 } else {
3106 for (reg_178 = reg178_center - 12;
3107 reg_178 <= reg178_center + 12; reg_178 += 12) {
3108 totalrank = 0;
3109 set_178(reg_178);
3110 FOR_POPULATED_RANKS_BACKWARDS {
3111 train_ram_at_178(info, channel, slot, rank,
3112 totalrank, reg_178, 0, niter,
3113 timings);
3114 totalrank++;
3115 }
3116 }
3117 }
3118
3119 set_178(reg178_center);
3120 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3121 u16 tm0;
3122
3123 tm0 =
3124 choose_training(info, channel, slot, rank, lane, timings,
3125 reg178_center);
3126 write_500(info, channel, tm0,
3127 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3128 write_500(info, channel,
3129 tm0 +
3130 info->training.
3131 lane_timings[1][channel][slot][rank][lane] -
3132 info->training.
3133 lane_timings[0][channel][slot][rank][lane],
3134 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3135 }
3136
3137 totalrank = 0;
3138 FOR_POPULATED_RANKS_BACKWARDS {
3139 try_timing_offsets(info, channel, slot, rank, totalrank);
3140 totalrank++;
3141 }
Felix Held04be2dd2018-07-29 04:53:22 +02003142 MCHBAR8(0x243) = saved_243[0];
3143 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003144 write_1d0(0, 0x142, 3, 1);
3145 info->training.reg178_center = reg178_center;
3146}
3147
3148static void ram_training(struct raminfo *info)
3149{
3150 u16 saved_fc4;
3151
Felix Held04be2dd2018-07-29 04:53:22 +02003152 saved_fc4 = MCHBAR16(0xfc4);
3153 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003154
3155 if (info->revision >= 8)
3156 read_4090(info);
3157
3158 if (!try_cached_training(info))
3159 do_ram_training(info);
3160 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3161 && info->clock_speed_index < 2)
3162 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003163 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003164}
3165
Martin Roth468d02c2019-10-23 21:44:42 -06003166static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003167{
Martin Roth468d02c2019-10-23 21:44:42 -06003168 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003169 if (a > b) {
3170 t = a;
3171 a = b;
3172 b = t;
3173 }
3174 /* invariant a < b. */
3175 while (a) {
3176 t = b % a;
3177 b = a;
3178 a = t;
3179 }
3180 return b;
3181}
3182
3183static inline int div_roundup(int a, int b)
3184{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003185 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003186}
3187
Martin Roth468d02c2019-10-23 21:44:42 -06003188static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003189{
3190 return (a * b) / gcd(a, b);
3191}
3192
3193struct stru1 {
3194 u8 freqs_reversed;
3195 u8 freq_diff_reduced;
3196 u8 freq_min_reduced;
3197 u8 divisor_f4_to_fmax;
3198 u8 divisor_f3_to_fmax;
3199 u8 freq4_to_max_remainder;
3200 u8 freq3_to_2_remainder;
3201 u8 freq3_to_2_remaindera;
3202 u8 freq4_to_2_remainder;
3203 int divisor_f3_to_f1, divisor_f4_to_f2;
3204 int common_time_unit_ps;
3205 int freq_max_reduced;
3206};
3207
3208static void
3209compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3210 int num_cycles_2, int num_cycles_1, int round_it,
3211 int add_freqs, struct stru1 *result)
3212{
3213 int g;
3214 int common_time_unit_ps;
3215 int freq1_reduced, freq2_reduced;
3216 int freq_min_reduced;
3217 int freq_max_reduced;
3218 int freq3, freq4;
3219
3220 g = gcd(freq1, freq2);
3221 freq1_reduced = freq1 / g;
3222 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003223 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3224 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003225
3226 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3227 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3228 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3229 if (add_freqs) {
3230 freq3 += freq2_reduced;
3231 freq4 += freq1_reduced;
3232 }
3233
3234 if (round_it) {
3235 result->freq3_to_2_remainder = 0;
3236 result->freq3_to_2_remaindera = 0;
3237 result->freq4_to_max_remainder = 0;
3238 result->divisor_f4_to_f2 = 0;
3239 result->divisor_f3_to_f1 = 0;
3240 } else {
3241 if (freq2_reduced < freq1_reduced) {
3242 result->freq3_to_2_remainder =
3243 result->freq3_to_2_remaindera =
3244 freq3 % freq1_reduced - freq1_reduced + 1;
3245 result->freq4_to_max_remainder =
3246 -(freq4 % freq1_reduced);
3247 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3248 result->divisor_f4_to_f2 =
3249 (freq4 -
3250 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3251 result->freq4_to_2_remainder =
3252 -(char)((freq1_reduced - freq2_reduced) +
3253 ((u8) freq4 -
3254 (freq1_reduced -
3255 freq2_reduced)) % (u8) freq2_reduced);
3256 } else {
3257 if (freq2_reduced > freq1_reduced) {
3258 result->freq4_to_max_remainder =
3259 (freq4 % freq2_reduced) - freq2_reduced + 1;
3260 result->freq4_to_2_remainder =
3261 freq4 % freq_max_reduced -
3262 freq_max_reduced + 1;
3263 } else {
3264 result->freq4_to_max_remainder =
3265 -(freq4 % freq2_reduced);
3266 result->freq4_to_2_remainder =
3267 -(char)(freq4 % freq_max_reduced);
3268 }
3269 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3270 result->divisor_f3_to_f1 =
3271 (freq3 -
3272 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3273 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3274 result->freq3_to_2_remaindera =
3275 -(char)((freq_max_reduced - freq_min_reduced) +
3276 (freq3 -
3277 (freq_max_reduced -
3278 freq_min_reduced)) % freq1_reduced);
3279 }
3280 }
3281 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3282 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3283 if (round_it) {
3284 if (freq2_reduced > freq1_reduced) {
3285 if (freq3 % freq_max_reduced)
3286 result->divisor_f3_to_fmax++;
3287 }
3288 if (freq2_reduced < freq1_reduced) {
3289 if (freq4 % freq_max_reduced)
3290 result->divisor_f4_to_fmax++;
3291 }
3292 }
3293 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3294 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3295 result->freq_min_reduced = freq_min_reduced;
3296 result->common_time_unit_ps = common_time_unit_ps;
3297 result->freq_max_reduced = freq_max_reduced;
3298}
3299
3300static void
3301set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3302 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3303 int num_cycles_4, int reverse)
3304{
3305 struct stru1 vv;
3306 char multiplier;
3307
3308 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3309 0, 1, &vv);
3310
3311 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003312 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003313 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3314 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3315 div_roundup(num_cycles_1,
3316 vv.common_time_unit_ps) +
3317 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3318 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3319
3320 u32 y =
3321 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3322 vv.freq_max_reduced * multiplier)
3323 | (vv.
3324 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3325 multiplier) << 16) | ((u8) (vv.
3326 freq_min_reduced
3327 *
3328 multiplier)
3329 << 24);
3330 u32 x =
3331 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3332 divisor_f3_to_f1
3333 << 16)
3334 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3335 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003336 MCHBAR32(reg) = y;
3337 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003338 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003339 MCHBAR32(reg + 4) = y;
3340 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003341 }
3342}
3343
3344static void
3345set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3346 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3347 int num_cycles_4)
3348{
3349 struct stru1 ratios1;
3350 struct stru1 ratios2;
3351
3352 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3353 0, 1, &ratios2);
3354 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3355 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003356 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003357 ratios1.freq4_to_max_remainder | (ratios2.
3358 freq4_to_max_remainder
3359 << 8)
3360 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3361 divisor_f4_to_fmax
3362 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003363 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3364 (ratios2.freq4_to_max_remainder << 8) |
3365 (ratios1.divisor_f4_to_fmax << 16) |
3366 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003367}
3368
3369static void
3370set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3371 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3372{
3373 struct stru1 ratios;
3374
3375 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3376 round_it, add_freqs, &ratios);
3377 switch (mode) {
3378 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003379 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3380 (ratios.freqs_reversed << 8);
3381 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3382 (ratios.freq4_to_max_remainder << 8) |
3383 (ratios.divisor_f3_to_fmax << 16) |
3384 (ratios.divisor_f4_to_fmax << 20) |
3385 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003386 break;
3387
3388 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003389 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3390 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003391 break;
3392
3393 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003394 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3395 (ratios.freq4_to_max_remainder << 8) |
3396 (ratios.divisor_f3_to_fmax << 16) |
3397 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003398 break;
3399
3400 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003401 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3402 (ratios.divisor_f4_to_fmax << 8) |
3403 (ratios.freqs_reversed << 12) |
3404 (ratios.freq_min_reduced << 16) |
3405 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406 break;
3407 }
3408}
3409
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003410static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003411{
3412 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3413 0, 1);
3414 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3415 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3416 1);
3417 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3418 frequency_11(info), 1231, 1524, 0, 1);
3419 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3420 frequency_11(info) / 2, 1278, 2008, 0, 1);
3421 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3422 1167, 1539, 0, 1);
3423 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3424 frequency_11(info) / 2, 1403, 1318, 0, 1);
3425 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3426 1);
3427 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3428 1);
3429 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3430 1, 1);
3431 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3432 1);
3433 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3434 frequency_11(info) / 2, 4000, 0, 0, 0);
3435 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3436 frequency_11(info) / 2, 4000, 4000, 0, 0);
3437
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003438 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003439 printk(RAM_SPEW, "[6dc] <= %x\n",
3440 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003441 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003442 } else
3443 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3444 info->delay46_ps[0], 0,
3445 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003446 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3447 frequency_11(info), 2500, 0, 0, 0);
3448 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3449 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003450 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003451 printk(RAM_SPEW, "[6e8] <= %x\n",
3452 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003453 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003454 } else
3455 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3456 info->delay46_ps[1], 0,
3457 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003458 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3459 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3460 470, 0);
3461 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3462 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3463 454, 459, 0);
3464 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3465 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3466 2588, 0);
3467 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3468 2405, 0);
3469 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3470 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3471 480, 0);
3472 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003473 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3474 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003475}
3476
3477static u16 get_max_timing(struct raminfo *info, int channel)
3478{
3479 int slot, rank, lane;
3480 u16 ret = 0;
3481
Felix Held04be2dd2018-07-29 04:53:22 +02003482 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003483 return 384;
3484
3485 if (info->revision < 8)
3486 return 256;
3487
3488 for (slot = 0; slot < NUM_SLOTS; slot++)
3489 for (rank = 0; rank < NUM_RANKS; rank++)
3490 if (info->populated_ranks[channel][slot][rank])
3491 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003492 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493 get_timing_register_addr
3494 (lane, 0, slot,
3495 rank), 9));
3496 return ret;
3497}
3498
3499static void set_274265(struct raminfo *info)
3500{
3501 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3502 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3503 int delay_e_over_cycle_ps;
3504 int cycletime_ps;
3505 int channel;
3506
3507 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003508 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003509 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3510 cycletime_ps =
3511 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3512 delay_d_ps =
3513 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3514 - info->some_delay_3_ps_rounded + 200;
3515 if (!
3516 ((info->silicon_revision == 0
3517 || info->silicon_revision == 1)
3518 && (info->revision >= 8)))
3519 delay_d_ps += halfcycle_ps(info) * 2;
3520 delay_d_ps +=
3521 halfcycle_ps(info) * (!info->revision_flag_1 +
3522 info->some_delay_2_halfcycles_ceil +
3523 2 * info->some_delay_1_cycle_floor +
3524 info->clock_speed_index +
3525 2 * info->cas_latency - 7 + 11);
3526 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3527
Felix Held04be2dd2018-07-29 04:53:22 +02003528 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3529 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3530 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003531 delay_d_ps += 650;
3532 delay_c_ps = delay_d_ps + 1800;
3533 if (delay_c_ps <= delay_a_ps)
3534 delay_e_ps = 0;
3535 else
3536 delay_e_ps =
3537 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3538 cycletime_ps);
3539
3540 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3541 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3542 delay_f_cycles =
3543 div_roundup(2500 - delay_e_over_cycle_ps,
3544 2 * halfcycle_ps(info));
3545 if (delay_f_cycles > delay_e_cycles) {
3546 info->delay46_ps[channel] = delay_e_ps;
3547 delay_e_cycles = 0;
3548 } else {
3549 info->delay46_ps[channel] =
3550 delay_e_over_cycle_ps +
3551 2 * halfcycle_ps(info) * delay_f_cycles;
3552 delay_e_cycles -= delay_f_cycles;
3553 }
3554
3555 if (info->delay46_ps[channel] < 2500) {
3556 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003557 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003558 }
3559 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3560 if (delay_b_ps <= delay_a_ps)
3561 delay_b_ps = 0;
3562 else
3563 delay_b_ps -= delay_a_ps;
3564 info->delay54_ps[channel] =
3565 cycletime_ps * div_roundup(delay_b_ps,
3566 cycletime_ps) -
3567 2 * halfcycle_ps(info) * delay_e_cycles;
3568 if (info->delay54_ps[channel] < 2500)
3569 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003570 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003571 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3572 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003573 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003574 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003575 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003576 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3577 4 * halfcycle_ps(info)) - 6;
3578 MCHBAR32((channel << 10) + 0x274) =
3579 info->training.reg274265[channel][1] |
3580 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003581 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003582 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3583 4 * halfcycle_ps(info)) + 1;
3584 MCHBAR16((channel << 10) + 0x265) =
3585 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003586 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003587 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003588 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003589 else
Felix Held04be2dd2018-07-29 04:53:22 +02003590 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003591}
3592
3593static void restore_274265(struct raminfo *info)
3594{
3595 int channel;
3596
3597 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003598 MCHBAR32((channel << 10) + 0x274) =
3599 (info->cached_training->reg274265[channel][0] << 16) |
3600 info->cached_training->reg274265[channel][1];
3601 MCHBAR16((channel << 10) + 0x265) =
3602 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003604 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003605 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003606 else
Felix Held04be2dd2018-07-29 04:53:22 +02003607 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608}
3609
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610static void dmi_setup(void)
3611{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003612 gav(DMIBAR8(0x254));
3613 DMIBAR8(0x254) = 0x1;
3614 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003615 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616
Angel Ponsd071c4d2020-09-14 23:51:35 +02003617 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618
3619 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3620 DEFAULT_GPIOBASE | 0x38);
3621 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3622}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003624void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003627 u16 ggc;
3628 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629
Felix Held04be2dd2018-07-29 04:53:22 +02003630 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3632 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003633 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003634 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636
3637 dmi_setup();
3638
Felix Held04be2dd2018-07-29 04:53:22 +02003639 MCHBAR16(0x1170) = 0xa880;
3640 MCHBAR8(0x11c1) = 0x1;
3641 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003642 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003644 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3645 /* 0 for 32MB */
3646 gfxsize = 0;
3647 }
3648
3649 ggc = 0xb00 | ((gfxsize + 5) << 4);
3650
Angel Pons16fe1e02020-07-22 16:12:33 +02003651 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652
3653 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003654 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655
3656 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003657 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003658 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003659 MCHBAR16_OR(0x2c30, 0x200);
3660 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003661 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003662 pci_read_config8(GMA, MSAC); // = 0x2
3663 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003664 RCBA8(0x2318);
3665 RCBA8(0x2318) = 0x47;
3666 RCBA8(0x2320);
3667 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668 }
3669
Felix Heldf83d80b2018-07-29 05:30:30 +02003670 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671
Angel Pons16fe1e02020-07-22 16:12:33 +02003672 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003673 gav(RCBA32(0x3428));
3674 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003675}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003677void raminit(const int s3resume, const u8 *spd_addrmap)
3678{
Martin Roth468d02c2019-10-23 21:44:42 -06003679 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003680 int i;
3681 struct raminfo info;
3682 u8 x2ca8;
3683 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003684 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003685
Felix Held04be2dd2018-07-29 04:53:22 +02003686 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003687
3688 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3689
Angel Pons16fe1e02020-07-22 16:12:33 +02003690 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691
3692 memset(&info, 0x5a, sizeof(info));
3693
3694 info.last_500_command[0] = 0;
3695 info.last_500_command[1] = 0;
3696
3697 info.fsb_frequency = 135 * 2;
3698 info.board_lane_delay[0] = 0x14;
3699 info.board_lane_delay[1] = 0x07;
3700 info.board_lane_delay[2] = 0x07;
3701 info.board_lane_delay[3] = 0x08;
3702 info.board_lane_delay[4] = 0x56;
3703 info.board_lane_delay[5] = 0x04;
3704 info.board_lane_delay[6] = 0x04;
3705 info.board_lane_delay[7] = 0x05;
3706 info.board_lane_delay[8] = 0x10;
3707
3708 info.training.reg_178 = 0;
3709 info.training.reg_10b = 0;
3710
Angel Ponsa3868292021-01-15 22:10:13 +01003711 /* Wait for some bit, maybe TXT clear. */
3712 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3713 ;
3714
3715 /* Wait for ME to be ready */
3716 intel_early_me_init();
3717 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718
3719 /* before SPD */
3720 timestamp_add_now(101);
3721
Felix Held29a9c072018-07-29 01:34:45 +02003722 if (!s3resume || 1) { // possible error
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 <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003770 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771 gav(info.
3772 spd[channel][0][useful_addresses
3773 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003774 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003775 useful_addresses
3776 [addr]));
3777 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3778 die("Only DDR3 is supported");
3779
3780 v = info.spd[channel][0][RANKS_AND_DQ];
3781 info.populated_ranks[channel][0][0] = 1;
3782 info.populated_ranks[channel][0][1] =
3783 ((v >> 3) & 7);
3784 if (((v >> 3) & 7) > 1)
3785 die("At most 2 ranks are supported");
3786 if ((v & 7) == 0 || (v & 7) > 2)
3787 die("Only x8 and x16 modules are supported");
3788 if ((info.
3789 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3790 && (info.
3791 spd[channel][slot][MODULE_TYPE] & 0xF)
3792 != 3)
3793 die("Registered memory is not supported");
3794 info.is_x16_module[channel][0] = (v & 7) - 1;
3795 info.density[channel][slot] =
3796 info.spd[channel][slot][DENSITY] & 0xF;
3797 if (!
3798 (info.
3799 spd[channel][slot][MEMORY_BUS_WIDTH] &
3800 0x18))
3801 info.use_ecc = 0;
3802 }
3803
3804 gav(0x55);
3805
3806 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3807 int v = 0;
3808 for (slot = 0; slot < NUM_SLOTS; slot++)
3809 for (rank = 0; rank < NUM_RANKS; rank++)
3810 v |= info.
3811 populated_ranks[channel][slot][rank]
3812 << (2 * slot + rank);
3813 info.populated_ranks_mask[channel] = v;
3814 }
3815
3816 gav(0x55);
3817
Angel Pons16fe1e02020-07-22 16:12:33 +02003818 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819 }
3820
3821 /* after SPD */
3822 timestamp_add_now(102);
3823
Felix Held04be2dd2018-07-29 04:53:22 +02003824 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003825
3826 collect_system_info(&info);
3827 calculate_timings(&info);
3828
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003829 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003830 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003831 if (x2ca8 == 0 && (reg8 & 0x80)) {
3832 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3833 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3834 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3835 */
3836
3837 /* Clear bit7. */
3838
3839 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3840 (reg8 & ~(1 << 7)));
3841
3842 printk(BIOS_INFO,
3843 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003844 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003845 }
3846 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003847
3848 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003849 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3850 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851
3852 compute_derived_timings(&info);
3853
3854 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003855 gav(MCHBAR8(0x164));
3856 MCHBAR8(0x164) = 0x26;
3857 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003858 }
3859
Felix Held04be2dd2018-07-29 04:53:22 +02003860 MCHBAR32_OR(0x18b4, 0x210000);
3861 MCHBAR32_OR(0x1890, 0x2000000);
3862 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863
Angel Ponsa457e352020-07-22 18:17:33 +02003864 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3865 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866
Felix Held04be2dd2018-07-29 04:53:22 +02003867 gav(MCHBAR16(0x2c10));
3868 MCHBAR16(0x2c10) = 0x412;
3869 gav(MCHBAR16(0x2c10));
3870 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
Felix Held04be2dd2018-07-29 04:53:22 +02003872 gav(MCHBAR8(0x2ca8)); // !!!!
3873 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874
Angel Ponsa457e352020-07-22 18:17:33 +02003875 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3876 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003877 gav(MCHBAR32(0x1c04)); // !!!!
3878 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879
3880 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003881 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003882 }
3883
Felix Held04be2dd2018-07-29 04:53:22 +02003884 MCHBAR32(0x18d8) = 0x120000;
3885 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003886 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3887 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003888 MCHBAR32(0x18d8) = 0x40000;
3889 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003890 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3891 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003892 MCHBAR32(0x18d8) = 0x180000;
3893 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003894 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003896 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003897
Felix Held04be2dd2018-07-29 04:53:22 +02003898 gav(MCHBAR32(0x18dc)); // !!!!
3899 MCHBAR32(0x18dc) = 0x3;
3900 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003901
3902 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003903 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003904 }
3905
Felix Held04be2dd2018-07-29 04:53:22 +02003906 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003907 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003908 MCHBAR32(0x1a10) = 0x4200010e;
3909 MCHBAR32_OR(0x18b8, 0x200);
3910 gav(MCHBAR32(0x1918)); // !!!!
3911 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
Felix Held04be2dd2018-07-29 04:53:22 +02003913 gav(MCHBAR32(0x18b8)); // !!!!
3914 MCHBAR32(0x18b8) = 0xe00;
3915 gav(MCHBAR32(0x182c)); // !!!!
3916 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003917 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3918 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003919 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3920 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921
Felix Held04be2dd2018-07-29 04:53:22 +02003922 MCHBAR32_AND(0x18b4, 0xffff7fff);
3923 gav(MCHBAR32(0x1a68)); // !!!!
3924 MCHBAR32(0x1a68) = 0x343800;
3925 gav(MCHBAR32(0x1e68)); // !!!!
3926 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
3928 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003929 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930 }
3931
Angel Pons08143572020-07-22 17:47:06 +02003932 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3933 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3934 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3935 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3936 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003937 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3938 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003939 gav(MCHBAR32(0x1af0)); // !!!!
3940 gav(MCHBAR32(0x1af0)); // !!!!
3941 MCHBAR32(0x1af0) = 0x1f020003;
3942 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003944 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003945 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003946 }
3947
Felix Held04be2dd2018-07-29 04:53:22 +02003948 gav(MCHBAR32(0x1890)); // !!!!
3949 MCHBAR32(0x1890) = 0x80102;
3950 gav(MCHBAR32(0x18b4)); // !!!!
3951 MCHBAR32(0x18b4) = 0x216000;
3952 MCHBAR32(0x18a4) = 0x22222222;
3953 MCHBAR32(0x18a8) = 0x22222222;
3954 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003955
3956 udelay(1000);
3957
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003958 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003959
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003960 if (x2ca8 == 0) {
3961 int j;
3962 if (s3resume && info.cached_training) {
3963 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003964 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003965 info.cached_training->reg2ca9_bit0);
3966 for (i = 0; i < 2; i++)
3967 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003968 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003969 i, j, info.cached_training->reg274265[i][j]);
3970 } else {
3971 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003972 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003973 info.training.reg2ca9_bit0);
3974 for (i = 0; i < 2; i++)
3975 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003976 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003977 i, j, info.training.reg274265[i][j]);
3978 }
3979
3980 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003981
3982 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003983 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984 }
3985
3986 udelay(1000);
3987
3988 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003989 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003990 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003991 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3992 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
3993 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003994
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003995 MCHBAR8(0x1150);
3996 MCHBAR8(0x1151);
3997 MCHBAR8(0x1022);
3998 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02003999 MCHBAR32(0x1300) = 0x60606060;
4000 MCHBAR32(0x1304) = 0x60606060;
4001 MCHBAR32(0x1308) = 0x78797a7b;
4002 MCHBAR32(0x130c) = 0x7c7d7e7f;
4003 MCHBAR32(0x1310) = 0x60606060;
4004 MCHBAR32(0x1314) = 0x60606060;
4005 MCHBAR32(0x1318) = 0x60606060;
4006 MCHBAR32(0x131c) = 0x60606060;
4007 MCHBAR32(0x1320) = 0x50515253;
4008 MCHBAR32(0x1324) = 0x54555657;
4009 MCHBAR32(0x1328) = 0x58595a5b;
4010 MCHBAR32(0x132c) = 0x5c5d5e5f;
4011 MCHBAR32(0x1330) = 0x40414243;
4012 MCHBAR32(0x1334) = 0x44454647;
4013 MCHBAR32(0x1338) = 0x48494a4b;
4014 MCHBAR32(0x133c) = 0x4c4d4e4f;
4015 MCHBAR32(0x1340) = 0x30313233;
4016 MCHBAR32(0x1344) = 0x34353637;
4017 MCHBAR32(0x1348) = 0x38393a3b;
4018 MCHBAR32(0x134c) = 0x3c3d3e3f;
4019 MCHBAR32(0x1350) = 0x20212223;
4020 MCHBAR32(0x1354) = 0x24252627;
4021 MCHBAR32(0x1358) = 0x28292a2b;
4022 MCHBAR32(0x135c) = 0x2c2d2e2f;
4023 MCHBAR32(0x1360) = 0x10111213;
4024 MCHBAR32(0x1364) = 0x14151617;
4025 MCHBAR32(0x1368) = 0x18191a1b;
4026 MCHBAR32(0x136c) = 0x1c1d1e1f;
4027 MCHBAR32(0x1370) = 0x10203;
4028 MCHBAR32(0x1374) = 0x4050607;
4029 MCHBAR32(0x1378) = 0x8090a0b;
4030 MCHBAR32(0x137c) = 0xc0d0e0f;
4031 MCHBAR8(0x11cc) = 0x4e;
4032 MCHBAR32(0x1110) = 0x73970404;
4033 MCHBAR32(0x1114) = 0x72960404;
4034 MCHBAR32(0x1118) = 0x6f950404;
4035 MCHBAR32(0x111c) = 0x6d940404;
4036 MCHBAR32(0x1120) = 0x6a930404;
4037 MCHBAR32(0x1124) = 0x68a41404;
4038 MCHBAR32(0x1128) = 0x66a21404;
4039 MCHBAR32(0x112c) = 0x63a01404;
4040 MCHBAR32(0x1130) = 0x609e1404;
4041 MCHBAR32(0x1134) = 0x5f9c1404;
4042 MCHBAR32(0x1138) = 0x5c961404;
4043 MCHBAR32(0x113c) = 0x58a02404;
4044 MCHBAR32(0x1140) = 0x54942404;
4045 MCHBAR32(0x1190) = 0x900080a;
4046 MCHBAR16(0x11c0) = 0xc40b;
4047 MCHBAR16(0x11c2) = 0x303;
4048 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004049 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004050 MCHBAR32(0x11b8) = 0x70c3000;
4051 MCHBAR8(0x11ec) = 0xa;
4052 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004053 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004054 MCHBAR16(0x11ca) = 0xfa;
4055 MCHBAR32(0x11e4) = 0x4e20;
4056 MCHBAR8(0x11bc) = 0xf;
4057 MCHBAR16(0x11da) = 0x19;
4058 MCHBAR16(0x11ba) = 0x470c;
4059 MCHBAR32(0x1680) = 0xe6ffe4ff;
4060 MCHBAR32(0x1684) = 0xdeffdaff;
4061 MCHBAR32(0x1688) = 0xd4ffd0ff;
4062 MCHBAR32(0x168c) = 0xccffc6ff;
4063 MCHBAR32(0x1690) = 0xc0ffbeff;
4064 MCHBAR32(0x1694) = 0xb8ffb0ff;
4065 MCHBAR32(0x1698) = 0xa8ff0000;
4066 MCHBAR32(0x169c) = 0xc00;
4067 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004068 }
4069
Felix Held04be2dd2018-07-29 04:53:22 +02004070 MCHBAR32(0x124c) = 0x15040d00;
4071 MCHBAR32(0x1250) = 0x7f0000;
4072 MCHBAR32(0x1254) = 0x1e220004;
4073 MCHBAR32(0x1258) = 0x4000004;
4074 MCHBAR32(0x1278) = 0x0;
4075 MCHBAR32(0x125c) = 0x0;
4076 MCHBAR32(0x1260) = 0x0;
4077 MCHBAR32(0x1264) = 0x0;
4078 MCHBAR32(0x1268) = 0x0;
4079 MCHBAR32(0x126c) = 0x0;
4080 MCHBAR32(0x1270) = 0x0;
4081 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004082 }
4083
4084 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004085 MCHBAR16(0x1214) = 0x320;
4086 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004087 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4088 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004089 MCHBAR32(0x1400) = 0x13040020;
4090 MCHBAR32(0x1404) = 0xe090120;
4091 MCHBAR32(0x1408) = 0x5120220;
4092 MCHBAR32(0x140c) = 0x5120330;
4093 MCHBAR32(0x1410) = 0xe090220;
4094 MCHBAR32(0x1414) = 0x1010001;
4095 MCHBAR32(0x1418) = 0x1110000;
4096 MCHBAR32(0x141c) = 0x9020020;
4097 MCHBAR32(0x1420) = 0xd090220;
4098 MCHBAR32(0x1424) = 0x2090220;
4099 MCHBAR32(0x1428) = 0x2090330;
4100 MCHBAR32(0x142c) = 0xd090220;
4101 MCHBAR32(0x1430) = 0x1010001;
4102 MCHBAR32(0x1434) = 0x1110000;
4103 MCHBAR32(0x1438) = 0x11040020;
4104 MCHBAR32(0x143c) = 0x4030220;
4105 MCHBAR32(0x1440) = 0x1060220;
4106 MCHBAR32(0x1444) = 0x1060330;
4107 MCHBAR32(0x1448) = 0x4030220;
4108 MCHBAR32(0x144c) = 0x1010001;
4109 MCHBAR32(0x1450) = 0x1110000;
4110 MCHBAR32(0x1454) = 0x4010020;
4111 MCHBAR32(0x1458) = 0xb090220;
4112 MCHBAR32(0x145c) = 0x1090220;
4113 MCHBAR32(0x1460) = 0x1090330;
4114 MCHBAR32(0x1464) = 0xb090220;
4115 MCHBAR32(0x1468) = 0x1010001;
4116 MCHBAR32(0x146c) = 0x1110000;
4117 MCHBAR32(0x1470) = 0xf040020;
4118 MCHBAR32(0x1474) = 0xa090220;
4119 MCHBAR32(0x1478) = 0x1120220;
4120 MCHBAR32(0x147c) = 0x1120330;
4121 MCHBAR32(0x1480) = 0xa090220;
4122 MCHBAR32(0x1484) = 0x1010001;
4123 MCHBAR32(0x1488) = 0x1110000;
4124 MCHBAR32(0x148c) = 0x7020020;
4125 MCHBAR32(0x1490) = 0x1010220;
4126 MCHBAR32(0x1494) = 0x10210;
4127 MCHBAR32(0x1498) = 0x10320;
4128 MCHBAR32(0x149c) = 0x1010220;
4129 MCHBAR32(0x14a0) = 0x1010001;
4130 MCHBAR32(0x14a4) = 0x1110000;
4131 MCHBAR32(0x14a8) = 0xd040020;
4132 MCHBAR32(0x14ac) = 0x8090220;
4133 MCHBAR32(0x14b0) = 0x1111310;
4134 MCHBAR32(0x14b4) = 0x1111420;
4135 MCHBAR32(0x14b8) = 0x8090220;
4136 MCHBAR32(0x14bc) = 0x1010001;
4137 MCHBAR32(0x14c0) = 0x1110000;
4138 MCHBAR32(0x14c4) = 0x3010020;
4139 MCHBAR32(0x14c8) = 0x7090220;
4140 MCHBAR32(0x14cc) = 0x1081310;
4141 MCHBAR32(0x14d0) = 0x1081420;
4142 MCHBAR32(0x14d4) = 0x7090220;
4143 MCHBAR32(0x14d8) = 0x1010001;
4144 MCHBAR32(0x14dc) = 0x1110000;
4145 MCHBAR32(0x14e0) = 0xb040020;
4146 MCHBAR32(0x14e4) = 0x2030220;
4147 MCHBAR32(0x14e8) = 0x1051310;
4148 MCHBAR32(0x14ec) = 0x1051420;
4149 MCHBAR32(0x14f0) = 0x2030220;
4150 MCHBAR32(0x14f4) = 0x1010001;
4151 MCHBAR32(0x14f8) = 0x1110000;
4152 MCHBAR32(0x14fc) = 0x5020020;
4153 MCHBAR32(0x1500) = 0x5090220;
4154 MCHBAR32(0x1504) = 0x2071310;
4155 MCHBAR32(0x1508) = 0x2071420;
4156 MCHBAR32(0x150c) = 0x5090220;
4157 MCHBAR32(0x1510) = 0x1010001;
4158 MCHBAR32(0x1514) = 0x1110000;
4159 MCHBAR32(0x1518) = 0x7040120;
4160 MCHBAR32(0x151c) = 0x2090220;
4161 MCHBAR32(0x1520) = 0x70b1210;
4162 MCHBAR32(0x1524) = 0x70b1310;
4163 MCHBAR32(0x1528) = 0x2090220;
4164 MCHBAR32(0x152c) = 0x1010001;
4165 MCHBAR32(0x1530) = 0x1110000;
4166 MCHBAR32(0x1534) = 0x1010110;
4167 MCHBAR32(0x1538) = 0x1081310;
4168 MCHBAR32(0x153c) = 0x5041200;
4169 MCHBAR32(0x1540) = 0x5041310;
4170 MCHBAR32(0x1544) = 0x1081310;
4171 MCHBAR32(0x1548) = 0x1010001;
4172 MCHBAR32(0x154c) = 0x1110000;
4173 MCHBAR32(0x1550) = 0x1040120;
4174 MCHBAR32(0x1554) = 0x4051210;
4175 MCHBAR32(0x1558) = 0xd051200;
4176 MCHBAR32(0x155c) = 0xd051200;
4177 MCHBAR32(0x1560) = 0x4051210;
4178 MCHBAR32(0x1564) = 0x1010001;
4179 MCHBAR32(0x1568) = 0x1110000;
4180 MCHBAR16(0x1222) = 0x220a;
4181 MCHBAR16(0x123c) = 0x1fc0;
4182 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004183 }
4184
Felix Heldf83d80b2018-07-29 05:30:30 +02004185 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004186 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004187 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004188
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004189 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004190
4191 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004192 MCHBAR8_AND(0x2ca8, ~3);
4193 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004194 /* This issues a CPU reset without resetting the platform */
4195 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004196 /* Write back the S3 state to PM1_CNT to let the reset CPU
4197 know it also needs to take the s3 path. */
4198 if (s3resume)
4199 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4200 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004201 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004202 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004203 }
4204
Felix Held04be2dd2018-07-29 04:53:22 +02004205 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004206 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02004207 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004208 MCHBAR16(0x2c20); // !!!!
4209 MCHBAR16(0x2c10); // !!!!
4210 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004211 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004212 udelay(1000);
4213 write_1d0(0, 0x33d, 0, 0);
4214 write_500(&info, 0, 0, 0xb61, 0, 0);
4215 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004216 MCHBAR32(0x1a30) = 0x0;
4217 MCHBAR32(0x1a34) = 0x0;
4218 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4219 (info.populated_ranks[0][0][0] * 0xa0);
4220 MCHBAR16(0x616) = 0x26a;
4221 MCHBAR32(0x134) = 0x856000;
4222 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004223 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4224 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004225 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004226 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4227 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004228 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004229 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004230 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4231 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004232 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4233 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4234 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4235 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4236 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4237 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4238 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4239 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4240 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4241 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004242 }
4243
4244 write_1d0(0x4, 0x151, 4, 1);
4245 write_1d0(0, 0x142, 3, 1);
4246 rdmsr(0x1ac); // !!!!
4247 write_500(&info, 1, 1, 0x6b3, 4, 1);
4248 write_500(&info, 1, 1, 0x6cf, 4, 1);
4249
Angel Pons244f4552021-01-15 20:41:36 +01004250 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251
4252 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4253 populated_ranks[0]
4254 [0][0]) << 0),
4255 0x1d1, 3, 1);
4256 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4258 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004259 }
4260
4261 set_334(0);
4262
4263 program_base_timings(&info);
4264
Felix Held04be2dd2018-07-29 04:53:22 +02004265 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004266
4267 write_1d0(0x2, 0x1d5, 2, 1);
4268 write_1d0(0x20, 0x166, 7, 1);
4269 write_1d0(0x0, 0xeb, 3, 1);
4270 write_1d0(0x0, 0xf3, 6, 1);
4271
4272 for (channel = 0; channel < NUM_CHANNELS; channel++)
4273 for (lane = 0; lane < 9; lane++) {
4274 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4275 u8 a;
4276 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4277 write_500(&info, channel, a, addr, 6, 1);
4278 }
4279
4280 udelay(1000);
4281
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004282 if (s3resume) {
4283 if (info.cached_training == NULL) {
4284 u32 reg32;
4285 printk(BIOS_ERR,
4286 "Couldn't find training data. Rebooting\n");
4287 reg32 = inl(DEFAULT_PMBASE + 0x04);
4288 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004289 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004290 }
4291 int tm;
4292 info.training = *info.cached_training;
4293 for (tm = 0; tm < 4; tm++)
4294 for (channel = 0; channel < NUM_CHANNELS; channel++)
4295 for (slot = 0; slot < NUM_SLOTS; slot++)
4296 for (rank = 0; rank < NUM_RANKS; rank++)
4297 for (lane = 0; lane < 9; lane++)
4298 write_500(&info,
4299 channel,
4300 info.training.
4301 lane_timings
4302 [tm][channel]
4303 [slot][rank]
4304 [lane],
4305 get_timing_register_addr
4306 (lane, tm,
4307 slot, rank),
4308 9, 0);
4309 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4310 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4311 }
4312
Felix Heldf83d80b2018-07-29 05:30:30 +02004313 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004314 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004315 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004316 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004317
4318 program_board_delay(&info);
4319
Felix Held04be2dd2018-07-29 04:53:22 +02004320 MCHBAR8(0x5ff) = 0x0;
4321 MCHBAR8(0x5ff) = 0x80;
4322 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323
Felix Held04be2dd2018-07-29 04:53:22 +02004324 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004325 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004326 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004327 gav(read_1d0(0x14b, 7)); // = 0x81023100
4328 write_1d0(0x30, 0x14b, 7, 1);
4329 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4330 write_1d0(7, 0xd6, 6, 1);
4331 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4332 write_1d0(7, 0x328, 6, 1);
4333
4334 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004335 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004336
4337 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4338 write_1d0(2, 0x116, 4, 1);
4339 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4340 write_1d0(0, 0xae, 6, 1);
4341 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4342 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004343 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4344 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004345 MCHBAR32_AND(0x140, ~0x07000000);
4346 MCHBAR32_AND(0x138, ~0x07000000);
4347 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004348 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004349 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004350 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004351
4352 {
4353 u32 t;
4354 u8 val_a1;
4355 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4356 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4357 rmw_1d0(0x320, 0x07,
Angel Pons244f4552021-01-15 20:41:36 +01004358 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004359 rmw_1d0(0x14b, 0x78,
4360 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004361 4), 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004362 rmw_1d0(0xce, 0x38,
4363 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004364 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365 }
4366
4367 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004368 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004369
Angel Pons244f4552021-01-15 20:41:36 +01004370 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004371 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004372 write_1d0(2, 0xae, 6, 1);
4373 write_1d0(2, 0x300, 6, 1);
4374 write_1d0(2, 0x121, 3, 1);
4375 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4376 write_1d0(4, 0xd6, 6, 1);
4377 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4378 write_1d0(4, 0x328, 6, 1);
4379
4380 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004381 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004382
Felix Held04be2dd2018-07-29 04:53:22 +02004383 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4384 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004385 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004386 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004387 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4388 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4389 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4390 write_1d0(0, 0x21c, 6, 1);
4391 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4392 write_1d0(0x35, 0x14b, 7, 1);
4393
4394 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004395 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004396
4397 set_334(1);
4398
Felix Held04be2dd2018-07-29 04:53:22 +02004399 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004400
4401 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4402 write_500(&info, channel,
4403 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4404 1);
4405 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4406 }
Felix Held04be2dd2018-07-29 04:53:22 +02004407 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4408 MCHBAR16(0x6c0) = 0x14a0;
4409 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4410 MCHBAR16(0x232) = 0x8;
4411 /* 0x40004 or 0 depending on ? */
4412 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4413 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4414 MCHBAR32(0x128) = 0x2150d05;
4415 MCHBAR8(0x12c) = 0x1f;
4416 MCHBAR8(0x12d) = 0x56;
4417 MCHBAR8(0x12e) = 0x31;
4418 MCHBAR8(0x12f) = 0x0;
4419 MCHBAR8(0x271) = 0x2;
4420 MCHBAR8(0x671) = 0x2;
4421 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004422 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004423 MCHBAR32(0x294 + (channel << 10)) =
4424 (info.populated_ranks_mask[channel] & 3) << 16;
4425 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4426 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004427 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004428 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4429 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004430
4431 if (!s3resume)
4432 jedec_init(&info);
4433
4434 int totalrank = 0;
4435 for (channel = 0; channel < NUM_CHANNELS; channel++)
4436 for (slot = 0; slot < NUM_SLOTS; slot++)
4437 for (rank = 0; rank < NUM_RANKS; rank++)
4438 if (info.populated_ranks[channel][slot][rank]) {
4439 jedec_read(&info, channel, slot, rank,
4440 totalrank, 0xa, 0x400);
4441 totalrank++;
4442 }
4443
Felix Held04be2dd2018-07-29 04:53:22 +02004444 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004445
Felix Heldf83d80b2018-07-29 05:30:30 +02004446 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4447 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004448
4449 if (!s3resume) {
4450 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004451 MCHBAR32(0x294 + (channel << 10)) =
4452 (info.populated_ranks_mask[channel] & 3) << 16;
4453 MCHBAR16(0x298 + (channel << 10)) =
4454 info.populated_ranks[channel][0][0] |
4455 (info.populated_ranks[channel][0][1] << 5);
4456 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004458 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004459
4460 {
4461 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004462 a = MCHBAR8(0x243);
4463 b = MCHBAR8(0x643);
4464 MCHBAR8(0x243) = a | 2;
4465 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004466 }
4467
4468 write_1d0(7, 0x19b, 3, 1);
4469 write_1d0(7, 0x1c0, 3, 1);
4470 write_1d0(4, 0x1c6, 4, 1);
4471 write_1d0(4, 0x1cc, 4, 1);
4472 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4473 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004474 MCHBAR32(0x584) = 0xfffff;
4475 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476
4477 for (channel = 0; channel < NUM_CHANNELS; channel++)
4478 for (slot = 0; slot < NUM_SLOTS; slot++)
4479 for (rank = 0; rank < NUM_RANKS; rank++)
4480 if (info.
4481 populated_ranks[channel][slot]
4482 [rank])
4483 config_rank(&info, s3resume,
4484 channel, slot,
4485 rank);
4486
Felix Held04be2dd2018-07-29 04:53:22 +02004487 MCHBAR8(0x243) = 0x1;
4488 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004489 }
4490
4491 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004492 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493 write_26c(0, 0x820);
4494 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004495 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004496 /* end */
4497
4498 if (s3resume) {
4499 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004500 MCHBAR32(0x294 + (channel << 10)) =
4501 (info.populated_ranks_mask[channel] & 3) << 16;
4502 MCHBAR16(0x298 + (channel << 10)) =
4503 info.populated_ranks[channel][0][0] |
4504 (info.populated_ranks[channel][0][1] << 5);
4505 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004507 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508 }
4509
Felix Held04be2dd2018-07-29 04:53:22 +02004510 MCHBAR32_AND(0xfa4, ~0x01000002);
4511 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 /* Before training. */
4514 timestamp_add_now(103);
4515
4516 if (!s3resume)
4517 ram_training(&info);
4518
4519 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004520 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004521
4522 dump_timings(&info);
4523
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524 program_modules_memory_map(&info, 0);
4525 program_total_memory_map(&info);
4526
4527 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004528 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004530 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004532 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533 else
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535
Felix Held04be2dd2018-07-29 04:53:22 +02004536 MCHBAR32_AND(0xfac, ~0x80000000);
4537 MCHBAR32(0xfb4) = 0x4800;
4538 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4539 MCHBAR32(0xe94) = 0x7ffff;
4540 MCHBAR32(0xfc0) = 0x80002040;
4541 MCHBAR32(0xfc4) = 0x701246;
4542 MCHBAR8_AND(0xfc8, ~0x70);
4543 MCHBAR32_OR(0xe5c, 0x1000000);
4544 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4545 MCHBAR32(0x50) = 0x700b0;
4546 MCHBAR32(0x3c) = 0x10;
4547 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4548 MCHBAR8_OR(0xff4, 0x2);
4549 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550
Felix Held04be2dd2018-07-29 04:53:22 +02004551 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4552 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4553 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004555 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4556 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4557 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 {
4560 u32 eax;
4561
4562 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4564 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4565 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 }
4567
4568 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004569 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572 else
Felix Held04be2dd2018-07-29 04:53:22 +02004573 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576
Felix Held04be2dd2018-07-29 04:53:22 +02004577 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 else
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582 }
4583
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
4586 {
4587 u8 al;
4588 al = 0xd;
4589 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4590 al += 2;
4591 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 }
4594
4595 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4597 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4598 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4599 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600 }
4601 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004602 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004603 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004604 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004605 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004606 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004607 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004608 MCHBAR8_OR(0x1210, 2);
4609 MCHBAR32(0x1200) = 0x8800440;
4610 MCHBAR32(0x1204) = 0x53ff0453;
4611 MCHBAR32(0x1208) = 0x19002043;
4612 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004613
4614 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004615 MCHBAR16(0x1214) = 0x220;
4616 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004617 }
4618
Felix Held04be2dd2018-07-29 04:53:22 +02004619 MCHBAR8_OR(0x1214, 0x4);
4620 MCHBAR8(0x120c) = 0x1;
4621 MCHBAR8(0x1218) = 0x3;
4622 MCHBAR8(0x121a) = 0x3;
4623 MCHBAR8(0x121c) = 0x3;
4624 MCHBAR16(0xc14) = 0x0;
4625 MCHBAR16(0xc20) = 0x0;
4626 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627
4628 /* revision dependent here. */
4629
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631
4632 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR16_OR(0x1230, 0x8000);
4636 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637
4638 u8 bl, ebpb;
4639 u16 reg_1020;
4640
Felix Held04be2dd2018-07-29 04:53:22 +02004641 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4642 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32(0x1000) = 0x100;
4645 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
4647 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649 bl = reg_1020 >> 8;
4650 ebpb = reg_1020 & 0xff;
4651 } else {
4652 ebpb = 0;
4653 bl = 8;
4654 }
4655
4656 rdmsr(0x1a2);
4657
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
Felix Held04be2dd2018-07-29 04:53:22 +02004664 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004665 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004666 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4667 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004668 }
4669
4670 setup_heci_uma(&info);
4671
4672 if (info.uma_enabled) {
4673 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32_OR(0x11b0, 0x4000);
4675 MCHBAR32_OR(0x11b4, 0x4000);
4676 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677
Felix Held04be2dd2018-07-29 04:53:22 +02004678 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4679 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4680 MCHBAR16_OR(0x1170, 0x1000);
4681
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004683
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004685 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004686 ;
4687 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688 }
4689
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004690 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4691 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 udelay(1000);
4696 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004697 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4698
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 if (!s3resume)
4700 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004701 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004702 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004703 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004704
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004705 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004706 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004707 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004708}