blob: 2f1ce066d334657dad477009ba5c40d8f70fab8a [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014 */
15
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +010017#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020020#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020021#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010022#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010023#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010024#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020027#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010028#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020029#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010030#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010031#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <timestamp.h>
33#include <cpu/x86/mtrr.h>
34#include <cpu/intel/speedstep.h>
35#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010036#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020037#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020038#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020040#include <types.h>
41
42#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010043#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020044#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020045#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010046
47#define NORTHBRIDGE PCI_DEV(0, 0, 0)
48#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
49#define GMA PCI_DEV (0, 0x2, 0x0)
50#define HECIDEV PCI_DEV(0, 0x16, 0)
51#define HECIBAR 0x10
52
53#define FOR_ALL_RANKS \
54 for (channel = 0; channel < NUM_CHANNELS; channel++) \
55 for (slot = 0; slot < NUM_SLOTS; slot++) \
56 for (rank = 0; rank < NUM_RANKS; rank++)
57
58#define FOR_POPULATED_RANKS \
59 for (channel = 0; channel < NUM_CHANNELS; channel++) \
60 for (slot = 0; slot < NUM_SLOTS; slot++) \
61 for (rank = 0; rank < NUM_RANKS; rank++) \
62 if (info->populated_ranks[channel][slot][rank])
63
64#define FOR_POPULATED_RANKS_BACKWARDS \
65 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
66 for (slot = 0; slot < NUM_SLOTS; slot++) \
67 for (rank = 0; rank < NUM_RANKS; rank++) \
68 if (info->populated_ranks[channel][slot][rank])
69
70/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
71typedef struct {
72 u8 smallest;
73 u8 largest;
74} timing_bounds_t[2][2][2][9];
75
Arthur Heymansdc71e252018-01-29 10:14:48 +010076#define MRC_CACHE_VERSION 1
77
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010078struct ram_training {
79 /* [TM][CHANNEL][SLOT][RANK][LANE] */
80 u16 lane_timings[4][2][2][2][9];
81 u16 reg_178;
82 u16 reg_10b;
83
84 u8 reg178_center;
85 u8 reg178_smallest;
86 u8 reg178_largest;
87 timing_bounds_t timing_bounds[2];
88 u16 timing_offset[2][2][2][9];
89 u16 timing2_offset[2][2][2][9];
90 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010091 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
92 u8 reg2ca9_bit0;
93 u32 reg_6dc;
94 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010095};
96
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097#include <lib.h> /* Prototypes */
98
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010099typedef struct _u128 {
100 u64 lo;
101 u64 hi;
102} u128;
103
104static void read128(u32 addr, u64 * out)
105{
106 u128 ret;
107 u128 stor;
108 asm volatile ("movdqu %%xmm0, %0\n"
109 "movdqa (%2), %%xmm0\n"
110 "movdqu %%xmm0, %1\n"
111 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
112 out[0] = ret.lo;
113 out[1] = ret.hi;
114}
115
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100116/* OK */
117static void write_1d0(u32 val, u16 addr, int bits, int flag)
118{
Felix Held04be2dd2018-07-29 04:53:22 +0200119 MCHBAR32(0x1d0) = 0;
120 while (MCHBAR32(0x1d0) & 0x800000)
121 ;
122 MCHBAR32(0x1d4) =
123 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
124 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200125 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200126 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100127}
128
129/* OK */
130static u16 read_1d0(u16 addr, int split)
131{
132 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200133 MCHBAR32(0x1d0) = 0;
134 while (MCHBAR32(0x1d0) & 0x800000)
135 ;
136 MCHBAR32(0x1d0) =
137 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
138 while (MCHBAR32(0x1d0) & 0x800000)
139 ;
140 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100141 write_1d0(0, 0x33d, 0, 0);
142 write_1d0(0, 0x33d, 0, 0);
143 val &= ((1 << split) - 1);
144 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
145 return val;
146}
147
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800148static void write32p(uintptr_t addr, uint32_t val)
149{
150 write32((void *)addr, val);
151}
152
153static uint32_t read32p(uintptr_t addr)
154{
155 return read32((void *)addr);
156}
157
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100158static void sfence(void)
159{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100160 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100161}
162
163static inline u16 get_lane_offset(int slot, int rank, int lane)
164{
165 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
166 0x452 * (lane == 8);
167}
168
169static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
170{
171 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
172 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
173}
174
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100175static u32 gav_real(int line, u32 in)
176{
177 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
178 return in;
179}
180
181#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200182
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100183struct raminfo {
184 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
185 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
186 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
187 u8 density[2][2]; /* [CHANNEL][SLOT] */
188 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
189 int rank_start[2][2][2];
190 u8 cas_latency;
191 u8 board_lane_delay[9];
192 u8 use_ecc;
193 u8 revision;
194 u8 max_supported_clock_speed_index;
195 u8 uma_enabled;
196 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
197 u8 silicon_revision;
198 u8 populated_ranks_mask[2];
199 u8 max_slots_used_in_channel;
200 u8 mode4030[2];
201 u16 avg4044[2];
202 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600203 unsigned int total_memory_mb;
204 unsigned int interleaved_part_mb;
205 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100206
207 u32 heci_bar;
208 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600209 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100210
211 struct ram_training training;
212 u32 last_500_command[2];
213
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214 u32 delay46_ps[2];
215 u32 delay54_ps[2];
216 u8 revision_flag_1;
217 u8 some_delay_1_cycle_floor;
218 u8 some_delay_2_halfcycles_ceil;
219 u8 some_delay_3_ps_rounded;
220
221 const struct ram_training *cached_training;
222};
223
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200224/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100225timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200226
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100227static void
228write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
229 int flag);
230
231/* OK */
232static u16
233read_500(struct raminfo *info, int channel, u16 addr, int split)
234{
235 u32 val;
236 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200237 MCHBAR32(0x500 + (channel << 10)) = 0;
238 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
239 ;
240 MCHBAR32(0x500 + (channel << 10)) =
241 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
242 + 0xb88 - addr);
243 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
244 ;
245 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100246 return val & ((1 << split) - 1);
247}
248
249/* OK */
250static void
251write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
252 int flag)
253{
254 if (info->last_500_command[channel] == 0x80000000) {
255 info->last_500_command[channel] = 0x40000000;
256 write_500(info, channel, 0, 0xb61, 0, 0);
257 }
Felix Held04be2dd2018-07-29 04:53:22 +0200258 MCHBAR32(0x500 + (channel << 10)) = 0;
259 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
260 ;
261 MCHBAR32(0x504 + (channel << 10)) =
262 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
263 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200264 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200265 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100266}
267
268static int rw_test(int rank)
269{
270 const u32 mask = 0xf00fc33c;
271 int ok = 0xff;
272 int i;
273 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800274 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100275 sfence();
276 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800277 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 sfence();
279 for (i = 0; i < 32; i++) {
280 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800281 write32p((rank << 28) | (i << 3), pat);
282 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100283 }
284 sfence();
285 for (i = 0; i < 32; i++) {
286 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
287 int j;
288 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800289 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100290 for (j = 0; j < 4; j++)
291 if (((val >> (j * 8)) & 0xff) != pat)
292 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800293 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100294 for (j = 0; j < 4; j++)
295 if (((val >> (j * 8)) & 0xff) != pat)
296 ok &= ~(16 << j);
297 }
298 sfence();
299 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800300 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100301 sfence();
302 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800303 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100304
305 return ok;
306}
307
308static void
309program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
310{
311 int lane;
312 for (lane = 0; lane < 8; lane++) {
313 write_500(info, channel,
314 base +
315 info->training.
316 lane_timings[2][channel][slot][rank][lane],
317 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
318 write_500(info, channel,
319 base +
320 info->training.
321 lane_timings[3][channel][slot][rank][lane],
322 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
323 }
324}
325
326static void write_26c(int channel, u16 si)
327{
Felix Held04be2dd2018-07-29 04:53:22 +0200328 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
329 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
330 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100331}
332
333static u32 get_580(int channel, u8 addr)
334{
335 u32 ret;
336 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200337 MCHBAR8(0x5ff) = 0x0;
338 MCHBAR8(0x5ff) = 0x80;
339 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
340 MCHBAR8_OR(0x580 + (channel << 10), 1);
341 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
342 ;
343 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100344 return ret;
345}
346
347const int cached_config = 0;
348
349#define NUM_CHANNELS 2
350#define NUM_SLOTS 2
351#define NUM_RANKS 2
352#define RANK_SHIFT 28
353#define CHANNEL_SHIFT 10
354
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100355static void seq9(struct raminfo *info, int channel, int slot, int rank)
356{
357 int i, lane;
358
359 for (i = 0; i < 2; i++)
360 for (lane = 0; lane < 8; lane++)
361 write_500(info, channel,
362 info->training.lane_timings[i +
363 1][channel][slot]
364 [rank][lane], get_timing_register_addr(lane,
365 i + 1,
366 slot,
367 rank),
368 9, 0);
369
370 write_1d0(1, 0x103, 6, 1);
371 for (lane = 0; lane < 8; lane++)
372 write_500(info, channel,
373 info->training.
374 lane_timings[0][channel][slot][rank][lane],
375 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
376
377 for (i = 0; i < 2; i++) {
378 for (lane = 0; lane < 8; lane++)
379 write_500(info, channel,
380 info->training.lane_timings[i +
381 1][channel][slot]
382 [rank][lane], get_timing_register_addr(lane,
383 i + 1,
384 slot,
385 rank),
386 9, 0);
387 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
388 }
389
390 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200391 MCHBAR8(0x5ff) = 0x0;
392 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100393 write_1d0(0x2, 0x142, 3, 1);
394 for (lane = 0; lane < 8; lane++) {
395 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
396 info->training.lane_timings[2][channel][slot][rank][lane] =
397 read_500(info, channel,
398 get_timing_register_addr(lane, 2, slot, rank), 9);
399 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
400 info->training.lane_timings[3][channel][slot][rank][lane] =
401 info->training.lane_timings[2][channel][slot][rank][lane] +
402 0x20;
403 }
404}
405
406static int count_ranks_in_channel(struct raminfo *info, int channel)
407{
408 int slot, rank;
409 int res = 0;
410 for (slot = 0; slot < NUM_SLOTS; slot++)
411 for (rank = 0; rank < NUM_SLOTS; rank++)
412 res += info->populated_ranks[channel][slot][rank];
413 return res;
414}
415
416static void
417config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
418{
419 int add;
420
421 write_1d0(0, 0x178, 7, 1);
422 seq9(info, channel, slot, rank);
423 program_timings(info, 0x80, channel, slot, rank);
424
425 if (channel == 0)
426 add = count_ranks_in_channel(info, 1);
427 else
428 add = 0;
429 if (!s3resume)
430 gav(rw_test(rank + add));
431 program_timings(info, 0x00, channel, slot, rank);
432 if (!s3resume)
433 gav(rw_test(rank + add));
434 if (!s3resume)
435 gav(rw_test(rank + add));
436 write_1d0(0, 0x142, 3, 1);
437 write_1d0(0, 0x103, 6, 1);
438
439 gav(get_580(channel, 0xc | (rank << 5)));
440 gav(read_1d0(0x142, 3));
441
Felix Held04be2dd2018-07-29 04:53:22 +0200442 MCHBAR8(0x5ff) = 0x0;
443 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100444}
445
446static void set_4cf(struct raminfo *info, int channel, u8 val)
447{
448 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
449 write_500(info, channel, val, 0x4cf, 4, 1);
450 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
451 write_500(info, channel, val, 0x659, 4, 1);
452 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
453 write_500(info, channel, val, 0x697, 4, 1);
454}
455
456static void set_334(int zero)
457{
458 int j, k, channel;
459 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
460 u32 vd8[2][16];
461
462 for (channel = 0; channel < NUM_CHANNELS; channel++) {
463 for (j = 0; j < 4; j++) {
464 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
465 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
466 u16 c;
467 if ((j == 0 || j == 3) && zero)
468 c = 0;
469 else if (j == 3)
470 c = 0x5f;
471 else
472 c = 0x5f5f;
473
474 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200475 MCHBAR32(0x138 + 8 * k) =
476 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100477 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200478 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100479 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200480 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100481 }
482
Felix Held22ca8cb2018-07-29 05:09:44 +0200483 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
484 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
486 zero ? 0 : (0x18191819 & lmask);
487 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
488 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
489 zero ? 0 : (a & lmask);
490 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100492 }
493 }
494
Felix Held04be2dd2018-07-29 04:53:22 +0200495 MCHBAR32_OR(0x130, 1);
496 while (MCHBAR8(0x130) & 1)
497 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100498}
499
500static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
501{
502 u32 v;
503 v = read_1d0(addr, split);
504 write_1d0((v & and) | or, addr, split, flag);
505}
506
507static int find_highest_bit_set(u16 val)
508{
509 int i;
510 for (i = 15; i >= 0; i--)
511 if (val & (1 << i))
512 return i;
513 return -1;
514}
515
516static int find_lowest_bit_set32(u32 val)
517{
518 int i;
519 for (i = 0; i < 32; i++)
520 if (val & (1 << i))
521 return i;
522 return -1;
523}
524
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100525enum {
526 DEVICE_TYPE = 2,
527 MODULE_TYPE = 3,
528 DENSITY = 4,
529 RANKS_AND_DQ = 7,
530 MEMORY_BUS_WIDTH = 8,
531 TIMEBASE_DIVIDEND = 10,
532 TIMEBASE_DIVISOR = 11,
533 CYCLETIME = 12,
534
535 CAS_LATENCIES_LSB = 14,
536 CAS_LATENCIES_MSB = 15,
537 CAS_LATENCY_TIME = 16,
538 THERMAL_AND_REFRESH = 31,
539 REFERENCE_RAW_CARD_USED = 62,
540 RANK1_ADDRESS_MAPPING = 63
541};
542
543static void calculate_timings(struct raminfo *info)
544{
Martin Roth468d02c2019-10-23 21:44:42 -0600545 unsigned int cycletime;
546 unsigned int cas_latency_time;
547 unsigned int supported_cas_latencies;
548 unsigned int channel, slot;
549 unsigned int clock_speed_index;
550 unsigned int min_cas_latency;
551 unsigned int cas_latency;
552 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100553
554 /* Find common CAS latency */
555 supported_cas_latencies = 0x3fe;
556 for (channel = 0; channel < NUM_CHANNELS; channel++)
557 for (slot = 0; slot < NUM_SLOTS; slot++)
558 if (info->populated_ranks[channel][slot][0])
559 supported_cas_latencies &=
560 2 *
561 (info->
562 spd[channel][slot][CAS_LATENCIES_LSB] |
563 (info->
564 spd[channel][slot][CAS_LATENCIES_MSB] <<
565 8));
566
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100567 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100568
569 cycletime = min_cycletime[max_clock_index];
570 cas_latency_time = min_cas_latency_time[max_clock_index];
571
572 for (channel = 0; channel < NUM_CHANNELS; channel++)
573 for (slot = 0; slot < NUM_SLOTS; slot++)
574 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600575 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100576 timebase =
577 1000 *
578 info->
579 spd[channel][slot][TIMEBASE_DIVIDEND] /
580 info->spd[channel][slot][TIMEBASE_DIVISOR];
581 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100582 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100583 timebase *
584 info->spd[channel][slot][CYCLETIME]);
585 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100586 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100587 timebase *
588 info->
589 spd[channel][slot][CAS_LATENCY_TIME]);
590 }
Jacob Garber3c193822019-06-10 18:23:32 -0600591 if (cycletime > min_cycletime[0])
592 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100593 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
594 if (cycletime == min_cycletime[clock_speed_index])
595 break;
596 if (cycletime > min_cycletime[clock_speed_index]) {
597 clock_speed_index--;
598 cycletime = min_cycletime[clock_speed_index];
599 break;
600 }
601 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100602 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100603 cas_latency = 0;
604 while (supported_cas_latencies) {
605 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
606 if (cas_latency <= min_cas_latency)
607 break;
608 supported_cas_latencies &=
609 ~(1 << find_highest_bit_set(supported_cas_latencies));
610 }
611
612 if (cas_latency != min_cas_latency && clock_speed_index)
613 clock_speed_index--;
614
615 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
616 die("Couldn't configure DRAM");
617 info->clock_speed_index = clock_speed_index;
618 info->cas_latency = cas_latency;
619}
620
621static void program_base_timings(struct raminfo *info)
622{
Martin Roth468d02c2019-10-23 21:44:42 -0600623 unsigned int channel;
624 unsigned int slot, rank, lane;
625 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100626 int i;
627
628 extended_silicon_revision = info->silicon_revision;
629 if (info->silicon_revision == 0)
630 for (channel = 0; channel < NUM_CHANNELS; channel++)
631 for (slot = 0; slot < NUM_SLOTS; slot++)
632 if ((info->
633 spd[channel][slot][MODULE_TYPE] & 0xF) ==
634 3)
635 extended_silicon_revision = 4;
636
637 for (channel = 0; channel < NUM_CHANNELS; channel++) {
638 for (slot = 0; slot < NUM_SLOTS; slot++)
639 for (rank = 0; rank < NUM_SLOTS; rank++) {
640 int card_timing_2;
641 if (!info->populated_ranks[channel][slot][rank])
642 continue;
643
644 for (lane = 0; lane < 9; lane++) {
645 int tm_reg;
646 int card_timing;
647
648 card_timing = 0;
649 if ((info->
650 spd[channel][slot][MODULE_TYPE] &
651 0xF) == 3) {
652 int reference_card;
653 reference_card =
654 info->
655 spd[channel][slot]
656 [REFERENCE_RAW_CARD_USED] &
657 0x1f;
658 if (reference_card == 3)
659 card_timing =
660 u16_ffd1188[0][lane]
661 [info->
662 clock_speed_index];
663 if (reference_card == 5)
664 card_timing =
665 u16_ffd1188[1][lane]
666 [info->
667 clock_speed_index];
668 }
669
670 info->training.
671 lane_timings[0][channel][slot][rank]
672 [lane] =
673 u8_FFFD1218[info->
674 clock_speed_index];
675 info->training.
676 lane_timings[1][channel][slot][rank]
677 [lane] = 256;
678
679 for (tm_reg = 2; tm_reg < 4; tm_reg++)
680 info->training.
681 lane_timings[tm_reg]
682 [channel][slot][rank][lane]
683 =
684 u8_FFFD1240[channel]
685 [extended_silicon_revision]
686 [lane][2 * slot +
687 rank][info->
688 clock_speed_index]
689 + info->max4048[channel]
690 +
691 u8_FFFD0C78[channel]
692 [extended_silicon_revision]
693 [info->
694 mode4030[channel]][slot]
695 [rank][info->
696 clock_speed_index]
697 + card_timing;
698 for (tm_reg = 0; tm_reg < 4; tm_reg++)
699 write_500(info, channel,
700 info->training.
701 lane_timings[tm_reg]
702 [channel][slot][rank]
703 [lane],
704 get_timing_register_addr
705 (lane, tm_reg, slot,
706 rank), 9, 0);
707 }
708
709 card_timing_2 = 0;
710 if (!(extended_silicon_revision != 4
711 || (info->
712 populated_ranks_mask[channel] & 5) ==
713 5)) {
714 if ((info->
715 spd[channel][slot]
716 [REFERENCE_RAW_CARD_USED] & 0x1F)
717 == 3)
718 card_timing_2 =
719 u16_FFFE0EB8[0][info->
720 clock_speed_index];
721 if ((info->
722 spd[channel][slot]
723 [REFERENCE_RAW_CARD_USED] & 0x1F)
724 == 5)
725 card_timing_2 =
726 u16_FFFE0EB8[1][info->
727 clock_speed_index];
728 }
729
730 for (i = 0; i < 3; i++)
731 write_500(info, channel,
732 (card_timing_2 +
733 info->max4048[channel]
734 +
735 u8_FFFD0EF8[channel]
736 [extended_silicon_revision]
737 [info->
738 mode4030[channel]][info->
739 clock_speed_index]),
740 u16_fffd0c50[i][slot][rank],
741 8, 1);
742 write_500(info, channel,
743 (info->max4048[channel] +
744 u8_FFFD0C78[channel]
745 [extended_silicon_revision][info->
746 mode4030
747 [channel]]
748 [slot][rank][info->
749 clock_speed_index]),
750 u16_fffd0c70[slot][rank], 7, 1);
751 }
752 if (!info->populated_ranks_mask[channel])
753 continue;
754 for (i = 0; i < 3; i++)
755 write_500(info, channel,
756 (info->max4048[channel] +
757 info->avg4044[channel]
758 +
759 u8_FFFD17E0[channel]
760 [extended_silicon_revision][info->
761 mode4030
762 [channel]][info->
763 clock_speed_index]),
764 u16_fffd0c68[i], 8, 1);
765 }
766}
767
768static unsigned int fsbcycle_ps(struct raminfo *info)
769{
770 return 900000 / info->fsb_frequency;
771}
772
773/* The time of DDR transfer in ps. */
774static unsigned int halfcycle_ps(struct raminfo *info)
775{
776 return 3750 / (info->clock_speed_index + 3);
777}
778
779/* The time of clock cycle in ps. */
780static unsigned int cycle_ps(struct raminfo *info)
781{
782 return 2 * halfcycle_ps(info);
783}
784
785/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600786static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100787{
788 return (info->clock_speed_index + 3) * 120;
789}
790
791/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600792static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100793{
794 return 100 * frequency_11(info) / 9;
795}
796
Martin Roth468d02c2019-10-23 21:44:42 -0600797static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100798{
799 return (frequency_11(info) * 2) * ps / 900000;
800}
801
Martin Roth468d02c2019-10-23 21:44:42 -0600802static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100803{
804 return (frequency_11(info)) * ns / 900;
805}
806
807static void compute_derived_timings(struct raminfo *info)
808{
Martin Roth468d02c2019-10-23 21:44:42 -0600809 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100810 int extended_silicon_revision;
811 int some_delay_1_ps;
812 int some_delay_2_ps;
813 int some_delay_2_halfcycles_ceil;
814 int some_delay_2_halfcycles_floor;
815 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100816 int some_delay_3_ps_rounded;
817 int some_delay_1_cycle_ceil;
818 int some_delay_1_cycle_floor;
819
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100820 some_delay_3_ps_rounded = 0;
821 extended_silicon_revision = info->silicon_revision;
822 if (!info->silicon_revision)
823 for (channel = 0; channel < NUM_CHANNELS; channel++)
824 for (slot = 0; slot < NUM_SLOTS; slot++)
825 if ((info->
826 spd[channel][slot][MODULE_TYPE] & 0xF) ==
827 3)
828 extended_silicon_revision = 4;
829 if (info->board_lane_delay[7] < 5)
830 info->board_lane_delay[7] = 5;
831 info->revision_flag_1 = 2;
832 if (info->silicon_revision == 2 || info->silicon_revision == 3)
833 info->revision_flag_1 = 0;
834 if (info->revision < 16)
835 info->revision_flag_1 = 0;
836
837 if (info->revision < 8)
838 info->revision_flag_1 = 0;
839 if (info->revision >= 8 && (info->silicon_revision == 0
840 || info->silicon_revision == 1))
841 some_delay_2_ps = 735;
842 else
843 some_delay_2_ps = 750;
844
845 if (info->revision >= 0x10 && (info->silicon_revision == 0
846 || info->silicon_revision == 1))
847 some_delay_1_ps = 3929;
848 else
849 some_delay_1_ps = 3490;
850
851 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
852 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
853 if (some_delay_1_ps % cycle_ps(info))
854 some_delay_1_cycle_ceil++;
855 else
856 some_delay_1_cycle_floor--;
857 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
858 if (info->revision_flag_1)
859 some_delay_2_ps = halfcycle_ps(info) >> 6;
860 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100861 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100862 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
863 375;
864 some_delay_3_ps =
865 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
866 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200867 if (some_delay_3_ps >= 150) {
868 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100869 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200870 some_delay_3_ps_rounded =
871 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
872 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100873 }
874 some_delay_2_halfcycles_ceil =
875 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
876 2 * (some_delay_1_cycle_ceil - 1);
877 if (info->revision_flag_1 && some_delay_3_ps < 150)
878 some_delay_2_halfcycles_ceil++;
879 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
880 if (info->revision < 0x10)
881 some_delay_2_halfcycles_floor =
882 some_delay_2_halfcycles_ceil - 1;
883 if (!info->revision_flag_1)
884 some_delay_2_halfcycles_floor++;
885 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
886 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
887 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
888 || (info->populated_ranks[1][0][0]
889 && info->populated_ranks[1][1][0]))
890 info->max_slots_used_in_channel = 2;
891 else
892 info->max_slots_used_in_channel = 1;
893 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200894 MCHBAR32(0x244 + (channel << 10)) =
895 ((info->revision < 8) ? 1 : 0x200) |
896 ((2 - info->max_slots_used_in_channel) << 17) |
897 (channel << 21) |
898 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100899 if (info->max_slots_used_in_channel == 1) {
900 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
901 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
902 } else {
903 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 */
904 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
905 || (count_ranks_in_channel(info, 1) ==
906 2)) ? 2 : 3;
907 }
908 for (channel = 0; channel < NUM_CHANNELS; channel++) {
909 int max_of_unk;
910 int min_of_unk_2;
911
912 int i, count;
913 int sum;
914
915 if (!info->populated_ranks_mask[channel])
916 continue;
917
918 max_of_unk = 0;
919 min_of_unk_2 = 32767;
920
921 sum = 0;
922 count = 0;
923 for (i = 0; i < 3; i++) {
924 int unk1;
925 if (info->revision < 8)
926 unk1 =
927 u8_FFFD1891[0][channel][info->
928 clock_speed_index]
929 [i];
930 else if (!
931 (info->revision >= 0x10
932 || info->revision_flag_1))
933 unk1 =
934 u8_FFFD1891[1][channel][info->
935 clock_speed_index]
936 [i];
937 else
938 unk1 = 0;
939 for (slot = 0; slot < NUM_SLOTS; slot++)
940 for (rank = 0; rank < NUM_RANKS; rank++) {
941 int a = 0;
942 int b = 0;
943
944 if (!info->
945 populated_ranks[channel][slot]
946 [rank])
947 continue;
948 if (extended_silicon_revision == 4
949 && (info->
950 populated_ranks_mask[channel] &
951 5) != 5) {
952 if ((info->
953 spd[channel][slot]
954 [REFERENCE_RAW_CARD_USED] &
955 0x1F) == 3) {
956 a = u16_ffd1178[0]
957 [info->
958 clock_speed_index];
959 b = u16_fe0eb8[0][info->
960 clock_speed_index];
961 } else
962 if ((info->
963 spd[channel][slot]
964 [REFERENCE_RAW_CARD_USED]
965 & 0x1F) == 5) {
966 a = u16_ffd1178[1]
967 [info->
968 clock_speed_index];
969 b = u16_fe0eb8[1][info->
970 clock_speed_index];
971 }
972 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100973 min_of_unk_2 = MIN(min_of_unk_2, a);
974 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100975 if (rank == 0) {
976 sum += a;
977 count++;
978 }
979 {
980 int t;
981 t = b +
982 u8_FFFD0EF8[channel]
983 [extended_silicon_revision]
984 [info->
985 mode4030[channel]][info->
986 clock_speed_index];
987 if (unk1 >= t)
988 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100989 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100990 unk1 - t);
991 }
992 }
993 {
994 int t =
995 u8_FFFD17E0[channel]
996 [extended_silicon_revision][info->
997 mode4030
998 [channel]]
999 [info->clock_speed_index] + min_of_unk_2;
1000 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001001 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001002 }
1003 }
1004
Jacob Garber64fb4a32019-06-10 17:29:18 -06001005 if (count == 0)
1006 die("No memory ranks found for channel %u\n", channel);
1007
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001008 info->avg4044[channel] = sum / count;
1009 info->max4048[channel] = max_of_unk;
1010 }
1011}
1012
1013static void jedec_read(struct raminfo *info,
1014 int channel, int slot, int rank,
1015 int total_rank, u8 addr3, unsigned int value)
1016{
1017 /* Handle mirrored mapping. */
1018 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001019 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1020 ((addr3 >> 1) & 0x10);
1021 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1022 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001023
1024 /* Handle mirrored mapping. */
1025 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1026 value =
1027 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1028 << 1);
1029
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001030 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001031
Felix Held04be2dd2018-07-29 04:53:22 +02001032 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1033 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001034
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001035 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001036}
1037
1038enum {
1039 MR1_RZQ12 = 512,
1040 MR1_RZQ2 = 64,
1041 MR1_RZQ4 = 4,
1042 MR1_ODS34OHM = 2
1043};
1044
1045enum {
1046 MR0_BT_INTERLEAVED = 8,
1047 MR0_DLL_RESET_ON = 256
1048};
1049
1050enum {
1051 MR2_RTT_WR_DISABLED = 0,
1052 MR2_RZQ2 = 1 << 10
1053};
1054
1055static void jedec_init(struct raminfo *info)
1056{
1057 int write_recovery;
1058 int channel, slot, rank;
1059 int total_rank;
1060 int dll_on;
1061 int self_refresh_temperature;
1062 int auto_self_refresh;
1063
1064 auto_self_refresh = 1;
1065 self_refresh_temperature = 1;
1066 if (info->board_lane_delay[3] <= 10) {
1067 if (info->board_lane_delay[3] <= 8)
1068 write_recovery = info->board_lane_delay[3] - 4;
1069 else
1070 write_recovery = 5;
1071 } else {
1072 write_recovery = 6;
1073 }
1074 FOR_POPULATED_RANKS {
1075 auto_self_refresh &=
1076 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1077 self_refresh_temperature &=
1078 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1079 }
1080 if (auto_self_refresh == 1)
1081 self_refresh_temperature = 0;
1082
1083 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1084 || (info->populated_ranks[0][0][0]
1085 && info->populated_ranks[0][1][0])
1086 || (info->populated_ranks[1][0][0]
1087 && info->populated_ranks[1][1][0]));
1088
1089 total_rank = 0;
1090
1091 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1092 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1093 int rzq_reg58e;
1094
1095 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1096 rzq_reg58e = 64;
1097 rtt = MR1_RZQ2;
1098 if (info->clock_speed_index != 0) {
1099 rzq_reg58e = 4;
1100 if (info->populated_ranks_mask[channel] == 3)
1101 rtt = MR1_RZQ4;
1102 }
1103 } else {
1104 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1105 rtt = MR1_RZQ12;
1106 rzq_reg58e = 64;
1107 rtt_wr = MR2_RZQ2;
1108 } else {
1109 rzq_reg58e = 4;
1110 rtt = MR1_RZQ4;
1111 }
1112 }
1113
Felix Held04be2dd2018-07-29 04:53:22 +02001114 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1115 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1116 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1117 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1118 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001119
1120 for (slot = 0; slot < NUM_SLOTS; slot++)
1121 for (rank = 0; rank < NUM_RANKS; rank++)
1122 if (info->populated_ranks[channel][slot][rank]) {
1123 jedec_read(info, channel, slot, rank,
1124 total_rank, 0x28,
1125 rtt_wr | (info->
1126 clock_speed_index
1127 << 3)
1128 | (auto_self_refresh << 6) |
1129 (self_refresh_temperature <<
1130 7));
1131 jedec_read(info, channel, slot, rank,
1132 total_rank, 0x38, 0);
1133 jedec_read(info, channel, slot, rank,
1134 total_rank, 0x18,
1135 rtt | MR1_ODS34OHM);
1136 jedec_read(info, channel, slot, rank,
1137 total_rank, 6,
1138 (dll_on << 12) |
1139 (write_recovery << 9)
1140 | ((info->cas_latency - 4) <<
1141 4) | MR0_BT_INTERLEAVED |
1142 MR0_DLL_RESET_ON);
1143 total_rank++;
1144 }
1145 }
1146}
1147
1148static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1149{
Martin Roth468d02c2019-10-23 21:44:42 -06001150 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001151 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1152 unsigned int channel_0_non_interleaved;
1153
1154 FOR_ALL_RANKS {
1155 if (info->populated_ranks[channel][slot][rank]) {
1156 total_mb[channel] +=
1157 pre_jedec ? 256 : (256 << info->
1158 density[channel][slot] >> info->
1159 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001160 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1161 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1162 (info->is_x16_module[channel][slot] |
1163 ((info->density[channel][slot] + 1) << 1))) |
1164 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001165 }
Felix Held04be2dd2018-07-29 04:53:22 +02001166 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1167 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001168 }
1169
1170 info->total_memory_mb = total_mb[0] + total_mb[1];
1171
1172 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001173 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174 info->non_interleaved_part_mb =
1175 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1176 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001177 MCHBAR32(0x100) = channel_0_non_interleaved |
1178 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001179 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001180 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001181}
1182
1183static void program_board_delay(struct raminfo *info)
1184{
1185 int cas_latency_shift;
1186 int some_delay_ns;
1187 int some_delay_3_half_cycles;
1188
Martin Roth468d02c2019-10-23 21:44:42 -06001189 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001190 int high_multiplier;
1191 int lane_3_delay;
1192 int cas_latency_derived;
1193
1194 high_multiplier = 0;
1195 some_delay_ns = 200;
1196 some_delay_3_half_cycles = 4;
1197 cas_latency_shift = info->silicon_revision == 0
1198 || info->silicon_revision == 1 ? 1 : 0;
1199 if (info->revision < 8) {
1200 some_delay_ns = 600;
1201 cas_latency_shift = 0;
1202 }
1203 {
1204 int speed_bit;
1205 speed_bit =
1206 ((info->clock_speed_index > 1
1207 || (info->silicon_revision != 2
1208 && info->silicon_revision != 3))) ^ (info->revision >=
1209 0x10);
1210 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1211 3, 1);
1212 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1213 3, 1);
1214 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1215 && (info->silicon_revision == 2
1216 || info->silicon_revision == 3))
1217 rmw_1d0(0x116, 5, 2, 4, 1);
1218 }
Felix Held04be2dd2018-07-29 04:53:22 +02001219 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1220 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001221
Felix Held04be2dd2018-07-29 04:53:22 +02001222 MCHBAR8(0x124) = info->board_lane_delay[4] +
1223 ((frequency_01(info) + 999) / 1000);
1224 MCHBAR16(0x125) = 0x1360;
1225 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001226 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001227 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001228 high_multiplier = 1;
1229 some_delay_2_half_cycles = ps_to_halfcycles(info,
1230 ((3 *
1231 fsbcycle_ps(info))
1232 >> 1) +
1233 (halfcycle_ps(info)
1234 *
1235 reg178_min[info->
1236 clock_speed_index]
1237 >> 6)
1238 +
1239 4 *
1240 halfcycle_ps(info)
1241 + 2230);
1242 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001243 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001244 (frequency_11(info) * 2) * (28 -
1245 some_delay_2_half_cycles) /
1246 (frequency_11(info) * 2 -
1247 4 * (info->fsb_frequency))) >> 3, 7);
1248 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001249 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001250 some_delay_3_half_cycles = 3;
1251 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001252 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1253 MCHBAR32(0x224 + (channel << 10)) =
1254 (info->max_slots_used_in_channel - 1) |
1255 ((info->cas_latency - 5 - info->clock_speed_index)
1256 << 21) | ((info->max_slots_used_in_channel +
1257 info->cas_latency - cas_latency_shift - 4) << 16) |
1258 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1259 ((info->cas_latency - info->clock_speed_index +
1260 info->max_slots_used_in_channel - 6) << 8);
1261 MCHBAR32(0x228 + (channel << 10)) =
1262 info->max_slots_used_in_channel;
1263 MCHBAR8(0x239 + (channel << 10)) = 32;
1264 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1265 (some_delay_3_half_cycles << 25) | 0x840000;
1266 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1267 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1268 MCHBAR32(0x24c + (channel << 10)) =
1269 ((!!info->clock_speed_index) << 17) |
1270 (((2 + info->clock_speed_index -
1271 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272
Felix Held04be2dd2018-07-29 04:53:22 +02001273 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1274 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1275 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001276
1277 write_500(info, channel,
1278 ((!info->populated_ranks[channel][1][1])
1279 | (!info->populated_ranks[channel][1][0] << 1)
1280 | (!info->populated_ranks[channel][0][1] << 2)
1281 | (!info->populated_ranks[channel][0][0] << 3)),
1282 0x4c9, 4, 1);
1283 }
1284
Felix Held22ca8cb2018-07-29 05:09:44 +02001285 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001286 {
1287 u8 freq_divisor = 2;
1288 if (info->fsb_frequency == frequency_11(info))
1289 freq_divisor = 3;
1290 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1291 freq_divisor = 1;
1292 else
1293 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001294 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001295 }
1296
1297 if (info->board_lane_delay[3] <= 10) {
1298 if (info->board_lane_delay[3] <= 8)
1299 lane_3_delay = info->board_lane_delay[3];
1300 else
1301 lane_3_delay = 10;
1302 } else {
1303 lane_3_delay = 12;
1304 }
1305 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1306 if (info->clock_speed_index > 1)
1307 cas_latency_derived++;
1308 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001309 MCHBAR32(0x240 + (channel << 10)) =
1310 ((info->clock_speed_index == 0) * 0x11000) |
1311 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1312 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001313 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1314 0x609, 6, 1);
1315 write_500(info, channel,
1316 info->clock_speed_index + 2 * info->cas_latency - 7,
1317 0x601, 6, 1);
1318
Felix Held04be2dd2018-07-29 04:53:22 +02001319 MCHBAR32(0x250 + (channel << 10)) =
1320 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1321 (info->board_lane_delay[7] << 2) |
1322 (info->board_lane_delay[4] << 16) |
1323 (info->board_lane_delay[1] << 25) |
1324 (info->board_lane_delay[1] << 29) | 1;
1325 MCHBAR32(0x254 + (channel << 10)) =
1326 (info->board_lane_delay[1] >> 3) |
1327 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1328 0x80 | (info->board_lane_delay[6] << 1) |
1329 (info->board_lane_delay[2] << 28) |
1330 (cas_latency_derived << 16) | 0x4700000;
1331 MCHBAR32(0x258 + (channel << 10)) =
1332 ((info->board_lane_delay[5] + info->clock_speed_index +
1333 9) << 12) | ((info->clock_speed_index -
1334 info->cas_latency + 12) << 8) |
1335 (info->board_lane_delay[2] << 17) |
1336 (info->board_lane_delay[4] << 24) | 0x47;
1337 MCHBAR32(0x25c + (channel << 10)) =
1338 (info->board_lane_delay[1] << 1) |
1339 (info->board_lane_delay[0] << 8) | 0x1da50000;
1340 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1341 MCHBAR8(0x5f8 + (channel << 10)) =
1342 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001343 }
1344
1345 program_modules_memory_map(info, 1);
1346
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001347 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001348 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1349 MCHBAR16_OR(0x612, 0x100);
1350 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001352 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001354 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001355 }
1356}
1357
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001358#define DEFAULT_PCI_MMIO_SIZE 2048
1359#define HOST_BRIDGE PCI_DEVFN(0, 0)
1360
1361static unsigned int get_mmio_size(void)
1362{
1363 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001364 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001365
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001366 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001367 if (dev)
1368 cfg = dev->chip_info;
1369
1370 /* If this is zero, it just means devicetree.cb didn't set it */
1371 if (!cfg || cfg->pci_mmio_size == 0)
1372 return DEFAULT_PCI_MMIO_SIZE;
1373 else
1374 return cfg->pci_mmio_size;
1375}
1376
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001377#define BETTER_MEMORY_MAP 0
1378
1379static void program_total_memory_map(struct raminfo *info)
1380{
1381 unsigned int TOM, TOLUD, TOUUD;
1382 unsigned int quickpath_reserved;
1383 unsigned int REMAPbase;
1384 unsigned int uma_base_igd;
1385 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001386 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387 int memory_remap;
1388 unsigned int memory_map[8];
1389 int i;
1390 unsigned int current_limit;
1391 unsigned int tseg_base;
1392 int uma_size_igd = 0, uma_size_gtt = 0;
1393
1394 memset(memory_map, 0, sizeof(memory_map));
1395
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001396 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001397 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001398 gav(t);
1399 const int uma_sizes_gtt[16] =
1400 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1401 /* Igd memory */
1402 const int uma_sizes_igd[16] = {
1403 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1404 256, 512
1405 };
1406
1407 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1408 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1409 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001410
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001411 mmio_size = get_mmio_size();
1412
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001413 TOM = info->total_memory_mb;
1414 if (TOM == 4096)
1415 TOM = 4032;
1416 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001417 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001418 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001419 memory_remap = 0;
1420 if (TOUUD - TOLUD > 64) {
1421 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001422 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 TOUUD = TOUUD - TOLUD + 4096;
1424 }
1425 if (TOUUD > 4096)
1426 memory_map[2] = TOUUD | 1;
1427 quickpath_reserved = 0;
1428
Jacob Garber975a7e32019-06-10 16:32:47 -06001429 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001430
Jacob Garber975a7e32019-06-10 16:32:47 -06001431 gav(t);
1432
1433 if (t & 0x800) {
1434 u32 shift = t >> 20;
1435 if (shift == 0)
1436 die("Quickpath value is 0\n");
1437 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001439
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 if (memory_remap)
1441 TOUUD -= quickpath_reserved;
1442
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 uma_base_igd = TOLUD - uma_size_igd;
1444 uma_base_gtt = uma_base_igd - uma_size_gtt;
1445 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1446 if (!memory_remap)
1447 tseg_base -= quickpath_reserved;
1448 tseg_base = ALIGN_DOWN(tseg_base, 8);
1449
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001450 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1451 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001453 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1454 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001456 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457
1458 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001459 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1460 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001462 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463
1464 current_limit = 0;
1465 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1466 memory_map[1] = 4096;
1467 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001468 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001469 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1471 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001472 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001473 }
1474}
1475
1476static void collect_system_info(struct raminfo *info)
1477{
1478 u32 capid0[3];
1479 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001480 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481
1482 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001483 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1484 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001485
1486 if (!info->heci_bar)
1487 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001488 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001489 if (!info->memory_reserved_for_heci_mb) {
1490 /* Wait for ME to be ready */
1491 intel_early_me_init();
1492 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1493 }
1494
1495 for (i = 0; i < 3; i++)
1496 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001497 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1498 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1500
1501 if ((capid0[1] >> 11) & 1)
1502 info->uma_enabled = 0;
1503 else
1504 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001505 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1507 info->silicon_revision = 0;
1508
1509 if (capid0[2] & 2) {
1510 info->silicon_revision = 0;
1511 info->max_supported_clock_speed_index = 2;
1512 for (channel = 0; channel < NUM_CHANNELS; channel++)
1513 if (info->populated_ranks[channel][0][0]
1514 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1515 3) {
1516 info->silicon_revision = 2;
1517 info->max_supported_clock_speed_index = 1;
1518 }
1519 } else {
1520 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1521 case 1:
1522 case 2:
1523 info->silicon_revision = 3;
1524 break;
1525 case 3:
1526 info->silicon_revision = 0;
1527 break;
1528 case 0:
1529 info->silicon_revision = 2;
1530 break;
1531 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001532 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001533 case 0x40:
1534 info->silicon_revision = 0;
1535 break;
1536 case 0x48:
1537 info->silicon_revision = 1;
1538 break;
1539 }
1540 }
1541}
1542
1543static void write_training_data(struct raminfo *info)
1544{
1545 int tm, channel, slot, rank, lane;
1546 if (info->revision < 8)
1547 return;
1548
1549 for (tm = 0; tm < 4; tm++)
1550 for (channel = 0; channel < NUM_CHANNELS; channel++)
1551 for (slot = 0; slot < NUM_SLOTS; slot++)
1552 for (rank = 0; rank < NUM_RANKS; rank++)
1553 for (lane = 0; lane < 9; lane++)
1554 write_500(info, channel,
1555 info->
1556 cached_training->
1557 lane_timings[tm]
1558 [channel][slot][rank]
1559 [lane],
1560 get_timing_register_addr
1561 (lane, tm, slot,
1562 rank), 9, 0);
1563 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1564 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1565}
1566
1567static void dump_timings(struct raminfo *info)
1568{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001570 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001571 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001572 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573 slot, rank);
1574 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001575 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001576 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001577 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 read_500(info, channel,
1579 get_timing_register_addr
1580 (lane, i, slot, rank),
1581 9),
1582 info->training.
1583 lane_timings[i][channel][slot][rank]
1584 [lane]);
1585 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001586 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001587 }
1588 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001589 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001590 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001591 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001593}
1594
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595/* Read timings and other registers that need to be restored verbatim and
1596 put them to CBMEM.
1597 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598static void save_timings(struct raminfo *info)
1599{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 int channel, slot, rank, lane, i;
1602
1603 train = info->training;
1604 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1605 for (i = 0; i < 4; i++)
1606 train.lane_timings[i][channel][slot][rank][lane] =
1607 read_500(info, channel,
1608 get_timing_register_addr(lane, i, slot,
1609 rank), 9);
1610 train.reg_178 = read_1d0(0x178, 7);
1611 train.reg_10b = read_1d0(0x10b, 6);
1612
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001613 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1614 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001615 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001616 train.reg274265[channel][0] = reg32 >> 16;
1617 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001618 train.reg274265[channel][2] =
1619 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001620 }
Felix Held04be2dd2018-07-29 04:53:22 +02001621 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1622 train.reg_6dc = MCHBAR32(0x6dc);
1623 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001624
Arthur Heymansb3282092019-04-14 17:53:28 +02001625 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1626 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001627
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001629 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1630 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001631}
1632
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001633static const struct ram_training *get_cached_training(void)
1634{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001635 struct region_device rdev;
1636 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1637 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001639 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641
1642/* FIXME: add timeout. */
1643static void wait_heci_ready(void)
1644{
Felix Held04be2dd2018-07-29 04:53:22 +02001645 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1646 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001647 write32((DEFAULT_HECIBAR + 0x4),
1648 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649}
1650
1651/* FIXME: add timeout. */
1652static void wait_heci_cb_avail(int len)
1653{
1654 union {
1655 struct mei_csr csr;
1656 u32 raw;
1657 } csr;
1658
Felix Held22ca8cb2018-07-29 05:09:44 +02001659 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1660 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001661
1662 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001663 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664 while (len >
1665 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001666 csr.csr.buffer_read_ptr))
1667 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668}
1669
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001670static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671{
1672 int len = (head->length + 3) / 4;
1673 int i;
1674
1675 wait_heci_cb_avail(len + 1);
1676
1677 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001678 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001679 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001680 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001682 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1683 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001684}
1685
1686static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001687send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688{
1689 struct mei_header head;
1690 int maxlen;
1691
1692 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001693 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001694
1695 while (len) {
1696 int cur = len;
1697 if (cur > maxlen) {
1698 cur = maxlen;
1699 head.is_complete = 0;
1700 } else
1701 head.is_complete = 1;
1702 head.length = cur;
1703 head.reserved = 0;
1704 head.client_address = clientaddress;
1705 head.host_address = hostaddress;
1706 send_heci_packet(&head, (u32 *) msg);
1707 len -= cur;
1708 msg += cur;
1709 }
1710}
1711
1712/* FIXME: Add timeout. */
1713static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001714recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1715 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716{
1717 union {
1718 struct mei_csr csr;
1719 u32 raw;
1720 } csr;
1721 int i = 0;
1722
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001725 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726 }
Felix Held04be2dd2018-07-29 04:53:22 +02001727 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1728 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 write32(DEFAULT_HECIBAR + 0x4,
1732 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733 *packet_size = 0;
1734 return 0;
1735 }
1736 if (head->length + 4 > 4 * csr.csr.buffer_depth
1737 || head->length > *packet_size) {
1738 *packet_size = 0;
1739 return -1;
1740 }
1741
1742 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001743 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001744 while (((head->length + 3) >> 2) >
1745 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1746 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001747
1748 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001749 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750 *packet_size = head->length;
1751 if (!csr.csr.ready)
1752 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001753 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754 return 0;
1755}
1756
1757/* FIXME: Add timeout. */
1758static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001759recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760{
1761 struct mei_header head;
1762 int current_position;
1763
1764 current_position = 0;
1765 while (1) {
1766 u32 current_size;
1767 current_size = *message_size - current_position;
1768 if (recv_heci_packet
1769 (info, &head, message + (current_position >> 2),
1770 &current_size) == -1)
1771 break;
1772 if (!current_size)
1773 break;
1774 current_position += current_size;
1775 if (head.is_complete) {
1776 *message_size = current_position;
1777 return 0;
1778 }
1779
1780 if (current_position >= *message_size)
1781 break;
1782 }
1783 *message_size = 0;
1784 return -1;
1785}
1786
1787static void send_heci_uma_message(struct raminfo *info)
1788{
1789 struct uma_reply {
1790 u8 group_id;
1791 u8 command;
1792 u8 reserved;
1793 u8 result;
1794 u8 field2;
1795 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001796 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001797 struct uma_message {
1798 u8 group_id;
1799 u8 cmd;
1800 u8 reserved;
1801 u8 result;
1802 u32 c2;
1803 u64 heci_uma_addr;
1804 u32 memory_reserved_for_heci_mb;
1805 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001806 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807 0, MKHI_SET_UMA, 0, 0,
1808 0x82,
1809 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1810 u32 reply_size;
1811
1812 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1813
1814 reply_size = sizeof(reply);
1815 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1816 return;
1817
1818 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1819 die("HECI init failed\n");
1820}
1821
1822static void setup_heci_uma(struct raminfo *info)
1823{
1824 u32 reg44;
1825
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001826 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827 info->memory_reserved_for_heci_mb = 0;
1828 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001829 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001830 return;
1831
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001832 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1834 info->heci_uma_addr =
1835 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001836 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001837 info->memory_reserved_for_heci_mb)) << 20;
1838
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001839 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001841 write32(DEFAULT_DMIBAR + 0x14,
1842 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1843 write32(DEFAULT_RCBA + 0x14,
1844 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1845 write32(DEFAULT_DMIBAR + 0x20,
1846 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1847 write32(DEFAULT_RCBA + 0x20,
1848 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1849 write32(DEFAULT_DMIBAR + 0x2c,
1850 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1851 write32(DEFAULT_RCBA + 0x30,
1852 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1853 write32(DEFAULT_DMIBAR + 0x38,
1854 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1855 write32(DEFAULT_RCBA + 0x40,
1856 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001857
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001858 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1859 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001860 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1861 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1862 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001863 }
1864
Felix Held04be2dd2018-07-29 04:53:22 +02001865 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866
1867 send_heci_uma_message(info);
1868
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001869 pci_write_config32(HECIDEV, 0x10, 0x0);
1870 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871
1872}
1873
1874static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1875{
1876 int ranks_in_channel;
1877 ranks_in_channel = info->populated_ranks[channel][0][0]
1878 + info->populated_ranks[channel][0][1]
1879 + info->populated_ranks[channel][1][0]
1880 + info->populated_ranks[channel][1][1];
1881
1882 /* empty channel */
1883 if (ranks_in_channel == 0)
1884 return 1;
1885
1886 if (ranks_in_channel != ranks)
1887 return 0;
1888 /* single slot */
1889 if (info->populated_ranks[channel][0][0] !=
1890 info->populated_ranks[channel][1][0])
1891 return 1;
1892 if (info->populated_ranks[channel][0][1] !=
1893 info->populated_ranks[channel][1][1])
1894 return 1;
1895 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1896 return 0;
1897 if (info->density[channel][0] != info->density[channel][1])
1898 return 0;
1899 return 1;
1900}
1901
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001902static void read_4090(struct raminfo *info)
1903{
1904 int i, channel, slot, rank, lane;
1905 for (i = 0; i < 2; i++)
1906 for (slot = 0; slot < NUM_SLOTS; slot++)
1907 for (rank = 0; rank < NUM_RANKS; rank++)
1908 for (lane = 0; lane < 9; lane++)
1909 info->training.
1910 lane_timings[0][i][slot][rank][lane]
1911 = 32;
1912
1913 for (i = 1; i < 4; i++)
1914 for (channel = 0; channel < NUM_CHANNELS; channel++)
1915 for (slot = 0; slot < NUM_SLOTS; slot++)
1916 for (rank = 0; rank < NUM_RANKS; rank++)
1917 for (lane = 0; lane < 9; lane++) {
1918 info->training.
1919 lane_timings[i][channel]
1920 [slot][rank][lane] =
1921 read_500(info, channel,
1922 get_timing_register_addr
1923 (lane, i, slot,
1924 rank), 9)
1925 + (i == 1) * 11; // !!!!
1926 }
1927
1928}
1929
1930static u32 get_etalon2(int flip, u32 addr)
1931{
1932 const u16 invmask[] = {
1933 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1934 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1935 };
1936 u32 ret;
1937 u32 comp4 = addr / 480;
1938 addr %= 480;
1939 u32 comp1 = addr & 0xf;
1940 u32 comp2 = (addr >> 4) & 1;
1941 u32 comp3 = addr >> 5;
1942
1943 if (comp4)
1944 ret = 0x1010101 << (comp4 - 1);
1945 else
1946 ret = 0;
1947 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1948 ret = ~ret;
1949
1950 return ret;
1951}
1952
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001953static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001954{
1955 msr_t msr = {.lo = 0, .hi = 0 };
1956
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001957 wrmsr(MTRR_PHYS_BASE(3), msr);
1958 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001959}
1960
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001961static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001962{
1963 msr_t msr;
1964 msr.lo = base | MTRR_TYPE_WRPROT;
1965 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001966 wrmsr(MTRR_PHYS_BASE(3), msr);
1967 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001968 & 0xffffffff);
1969 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001970 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001971}
1972
1973static void flush_cache(u32 start, u32 size)
1974{
1975 u32 end;
1976 u32 addr;
1977
1978 end = start + (ALIGN_DOWN(size + 4096, 4096));
1979 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001980 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001981}
1982
1983static void clear_errors(void)
1984{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001985 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001986}
1987
1988static void write_testing(struct raminfo *info, int totalrank, int flip)
1989{
1990 int nwrites = 0;
1991 /* in 8-byte units. */
1992 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001993 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001994
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001995 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001996 for (offset = 0; offset < 9 * 480; offset += 2) {
1997 write32(base + offset * 8, get_etalon2(flip, offset));
1998 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1999 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2000 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2001 nwrites += 4;
2002 if (nwrites >= 320) {
2003 clear_errors();
2004 nwrites = 0;
2005 }
2006 }
2007}
2008
2009static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2010{
2011 u8 failmask = 0;
2012 int i;
2013 int comp1, comp2, comp3;
2014 u32 failxor[2] = { 0, 0 };
2015
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002016 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002017
2018 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2019 for (comp1 = 0; comp1 < 4; comp1++)
2020 for (comp2 = 0; comp2 < 60; comp2++) {
2021 u32 re[4];
2022 u32 curroffset =
2023 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2024 read128((total_rank << 28) | (curroffset << 3),
2025 (u64 *) re);
2026 failxor[0] |=
2027 get_etalon2(flip, curroffset) ^ re[0];
2028 failxor[1] |=
2029 get_etalon2(flip, curroffset) ^ re[1];
2030 failxor[0] |=
2031 get_etalon2(flip, curroffset | 1) ^ re[2];
2032 failxor[1] |=
2033 get_etalon2(flip, curroffset | 1) ^ re[3];
2034 }
2035 for (i = 0; i < 8; i++)
2036 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2037 failmask |= 1 << i;
2038 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002039 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002040 flush_cache((total_rank << 28), 1728 * 5 * 4);
2041 return failmask;
2042}
2043
2044const u32 seed1[0x18] = {
2045 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2046 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2047 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2048 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2049 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2050 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2051};
2052
2053static u32 get_seed2(int a, int b)
2054{
2055 const u32 seed2[5] = {
2056 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2057 0x5b6db6db,
2058 };
2059 u32 r;
2060 r = seed2[(a + (a >= 10)) / 5];
2061 return b ? ~r : r;
2062}
2063
2064static int make_shift(int comp2, int comp5, int x)
2065{
2066 const u8 seed3[32] = {
2067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2068 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2069 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2070 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2071 };
2072
2073 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2074}
2075
2076static u32 get_etalon(int flip, u32 addr)
2077{
2078 u32 mask_byte = 0;
2079 int comp1 = (addr >> 1) & 1;
2080 int comp2 = (addr >> 3) & 0x1f;
2081 int comp3 = (addr >> 8) & 0xf;
2082 int comp4 = (addr >> 12) & 0xf;
2083 int comp5 = (addr >> 16) & 0x1f;
2084 u32 mask_bit = ~(0x10001 << comp3);
2085 u32 part1;
2086 u32 part2;
2087 int byte;
2088
2089 part2 =
2090 ((seed1[comp5] >>
2091 make_shift(comp2, comp5,
2092 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2093 part1 =
2094 ((seed1[comp5] >>
2095 make_shift(comp2, comp5,
2096 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2097
2098 for (byte = 0; byte < 4; byte++)
2099 if ((get_seed2(comp5, comp4) >>
2100 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2101 mask_byte |= 0xff << (8 * byte);
2102
2103 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2104 (comp3 + 16));
2105}
2106
2107static void
2108write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2109 char flip)
2110{
2111 int i;
2112 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002113 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2114 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002115}
2116
2117static u8
2118check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2119 char flip)
2120{
2121 u8 failmask = 0;
2122 u32 failxor[2];
2123 int i;
2124 int comp1, comp2, comp3;
2125
2126 failxor[0] = 0;
2127 failxor[1] = 0;
2128
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002129 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002130 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2131 for (comp1 = 0; comp1 < 16; comp1++)
2132 for (comp2 = 0; comp2 < 64; comp2++) {
2133 u32 addr =
2134 (totalrank << 28) | (region << 25) | (block
2135 << 16)
2136 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2137 2);
2138 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002139 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002140 }
2141 for (i = 0; i < 8; i++)
2142 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2143 failmask |= 1 << i;
2144 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002145 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002146 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2147 return failmask;
2148}
2149
2150static int check_bounded(unsigned short *vals, u16 bound)
2151{
2152 int i;
2153
2154 for (i = 0; i < 8; i++)
2155 if (vals[i] < bound)
2156 return 0;
2157 return 1;
2158}
2159
2160enum state {
2161 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2162};
2163
2164static int validate_state(enum state *in)
2165{
2166 int i;
2167 for (i = 0; i < 8; i++)
2168 if (in[i] != COMPLETE)
2169 return 0;
2170 return 1;
2171}
2172
2173static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002174do_fsm(enum state *state, u16 *counter,
2175 u8 fail_mask, int margin, int uplimit,
2176 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002177{
2178 int lane;
2179
2180 for (lane = 0; lane < 8; lane++) {
2181 int is_fail = (fail_mask >> lane) & 1;
2182 switch (state[lane]) {
2183 case BEFORE_USABLE:
2184 if (!is_fail) {
2185 counter[lane] = 1;
2186 state[lane] = AT_USABLE;
2187 break;
2188 }
2189 counter[lane] = 0;
2190 state[lane] = BEFORE_USABLE;
2191 break;
2192 case AT_USABLE:
2193 if (!is_fail) {
2194 ++counter[lane];
2195 if (counter[lane] >= margin) {
2196 state[lane] = AT_MARGIN;
2197 res_low[lane] = val - margin + 1;
2198 break;
2199 }
2200 state[lane] = 1;
2201 break;
2202 }
2203 counter[lane] = 0;
2204 state[lane] = BEFORE_USABLE;
2205 break;
2206 case AT_MARGIN:
2207 if (is_fail) {
2208 state[lane] = COMPLETE;
2209 res_high[lane] = val - 1;
2210 } else {
2211 counter[lane]++;
2212 state[lane] = AT_MARGIN;
2213 if (val == uplimit) {
2214 state[lane] = COMPLETE;
2215 res_high[lane] = uplimit;
2216 }
2217 }
2218 break;
2219 case COMPLETE:
2220 break;
2221 }
2222 }
2223}
2224
2225static void
2226train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2227 u8 total_rank, u8 reg_178, int first_run, int niter,
2228 timing_bounds_t * timings)
2229{
2230 int lane;
2231 enum state state[8];
2232 u16 count[8];
2233 u8 lower_usable[8];
2234 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002235 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002236 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002237 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002238
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002239 for (i = 0; i < 8; i++)
2240 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002241
2242 if (!first_run) {
2243 int is_all_ok = 1;
2244 for (lane = 0; lane < 8; lane++)
2245 if (timings[reg_178][channel][slot][rank][lane].
2246 smallest ==
2247 timings[reg_178][channel][slot][rank][lane].
2248 largest) {
2249 timings[reg_178][channel][slot][rank][lane].
2250 smallest = 0;
2251 timings[reg_178][channel][slot][rank][lane].
2252 largest = 0;
2253 is_all_ok = 0;
2254 }
2255 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002256 for (i = 0; i < 8; i++)
2257 state[i] = COMPLETE;
2258 }
2259 }
2260
2261 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2262 u8 failmask = 0;
2263 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2264 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2265 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002266 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002267 do_fsm(state, count, failmask, 5, 47, lower_usable,
2268 upper_usable, reg1b3);
2269 }
2270
2271 if (reg1b3) {
2272 write_1d0(0, 0x1b3, 6, 1);
2273 write_1d0(0, 0x1a3, 6, 1);
2274 for (lane = 0; lane < 8; lane++) {
2275 if (state[lane] == COMPLETE) {
2276 timings[reg_178][channel][slot][rank][lane].
2277 smallest =
2278 lower_usable[lane] +
2279 (info->training.
2280 lane_timings[0][channel][slot][rank][lane]
2281 & 0x3F) - 32;
2282 timings[reg_178][channel][slot][rank][lane].
2283 largest =
2284 upper_usable[lane] +
2285 (info->training.
2286 lane_timings[0][channel][slot][rank][lane]
2287 & 0x3F) - 32;
2288 }
2289 }
2290 }
2291
2292 if (!first_run) {
2293 for (lane = 0; lane < 8; lane++)
2294 if (state[lane] == COMPLETE) {
2295 write_500(info, channel,
2296 timings[reg_178][channel][slot][rank]
2297 [lane].smallest,
2298 get_timing_register_addr(lane, 0,
2299 slot, rank),
2300 9, 1);
2301 write_500(info, channel,
2302 timings[reg_178][channel][slot][rank]
2303 [lane].smallest +
2304 info->training.
2305 lane_timings[1][channel][slot][rank]
2306 [lane]
2307 -
2308 info->training.
2309 lane_timings[0][channel][slot][rank]
2310 [lane], get_timing_register_addr(lane,
2311 1,
2312 slot,
2313 rank),
2314 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002315 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002316 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002317 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002318
2319 do {
2320 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002321 for (i = 0; i < niter; i++) {
2322 if (failmask == 0xFF)
2323 break;
2324 failmask |=
2325 check_testing_type2(info, total_rank, 2, i,
2326 0);
2327 failmask |=
2328 check_testing_type2(info, total_rank, 3, i,
2329 1);
2330 }
Felix Held04be2dd2018-07-29 04:53:22 +02002331 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002332 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002333 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334 if ((1 << lane) & failmask) {
2335 if (timings[reg_178][channel]
2336 [slot][rank][lane].
2337 largest <=
2338 timings[reg_178][channel]
2339 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002340 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002341 [lane] = -1;
2342 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002343 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002344 [lane] = 0;
2345 timings[reg_178]
2346 [channel][slot]
2347 [rank][lane].
2348 smallest++;
2349 write_500(info, channel,
2350 timings
2351 [reg_178]
2352 [channel]
2353 [slot][rank]
2354 [lane].
2355 smallest,
2356 get_timing_register_addr
2357 (lane, 0,
2358 slot, rank),
2359 9, 1);
2360 write_500(info, channel,
2361 timings
2362 [reg_178]
2363 [channel]
2364 [slot][rank]
2365 [lane].
2366 smallest +
2367 info->
2368 training.
2369 lane_timings
2370 [1][channel]
2371 [slot][rank]
2372 [lane]
2373 -
2374 info->
2375 training.
2376 lane_timings
2377 [0][channel]
2378 [slot][rank]
2379 [lane],
2380 get_timing_register_addr
2381 (lane, 1,
2382 slot, rank),
2383 9, 1);
2384 }
2385 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002386 num_successfully_checked[lane]
2387 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002388 }
2389 }
Felix Held04be2dd2018-07-29 04:53:22 +02002390 while (!check_bounded(num_successfully_checked, 2))
2391 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002392
2393 for (lane = 0; lane < 8; lane++)
2394 if (state[lane] == COMPLETE) {
2395 write_500(info, channel,
2396 timings[reg_178][channel][slot][rank]
2397 [lane].largest,
2398 get_timing_register_addr(lane, 0,
2399 slot, rank),
2400 9, 1);
2401 write_500(info, channel,
2402 timings[reg_178][channel][slot][rank]
2403 [lane].largest +
2404 info->training.
2405 lane_timings[1][channel][slot][rank]
2406 [lane]
2407 -
2408 info->training.
2409 lane_timings[0][channel][slot][rank]
2410 [lane], get_timing_register_addr(lane,
2411 1,
2412 slot,
2413 rank),
2414 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002415 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002416 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002417 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002418
2419 do {
2420 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 for (i = 0; i < niter; i++) {
2422 if (failmask == 0xFF)
2423 break;
2424 failmask |=
2425 check_testing_type2(info, total_rank, 2, i,
2426 0);
2427 failmask |=
2428 check_testing_type2(info, total_rank, 3, i,
2429 1);
2430 }
2431
Felix Held04be2dd2018-07-29 04:53:22 +02002432 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002433 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002434 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002435 if ((1 << lane) & failmask) {
2436 if (timings[reg_178][channel]
2437 [slot][rank][lane].
2438 largest <=
2439 timings[reg_178][channel]
2440 [slot][rank][lane].
2441 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002442 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002443 [lane] = -1;
2444 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002445 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002446 [lane] = 0;
2447 timings[reg_178]
2448 [channel][slot]
2449 [rank][lane].
2450 largest--;
2451 write_500(info, channel,
2452 timings
2453 [reg_178]
2454 [channel]
2455 [slot][rank]
2456 [lane].
2457 largest,
2458 get_timing_register_addr
2459 (lane, 0,
2460 slot, rank),
2461 9, 1);
2462 write_500(info, channel,
2463 timings
2464 [reg_178]
2465 [channel]
2466 [slot][rank]
2467 [lane].
2468 largest +
2469 info->
2470 training.
2471 lane_timings
2472 [1][channel]
2473 [slot][rank]
2474 [lane]
2475 -
2476 info->
2477 training.
2478 lane_timings
2479 [0][channel]
2480 [slot][rank]
2481 [lane],
2482 get_timing_register_addr
2483 (lane, 1,
2484 slot, rank),
2485 9, 1);
2486 }
2487 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002488 num_successfully_checked[lane]
2489 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002490 }
2491 }
2492 }
Felix Held04be2dd2018-07-29 04:53:22 +02002493 while (!check_bounded(num_successfully_checked, 3))
2494 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002495
2496 for (lane = 0; lane < 8; lane++) {
2497 write_500(info, channel,
2498 info->training.
2499 lane_timings[0][channel][slot][rank][lane],
2500 get_timing_register_addr(lane, 0, slot, rank),
2501 9, 1);
2502 write_500(info, channel,
2503 info->training.
2504 lane_timings[1][channel][slot][rank][lane],
2505 get_timing_register_addr(lane, 1, slot, rank),
2506 9, 1);
2507 if (timings[reg_178][channel][slot][rank][lane].
2508 largest <=
2509 timings[reg_178][channel][slot][rank][lane].
2510 smallest) {
2511 timings[reg_178][channel][slot][rank][lane].
2512 largest = 0;
2513 timings[reg_178][channel][slot][rank][lane].
2514 smallest = 0;
2515 }
2516 }
2517 }
2518}
2519
2520static void set_10b(struct raminfo *info, u8 val)
2521{
2522 int channel;
2523 int slot, rank;
2524 int lane;
2525
2526 if (read_1d0(0x10b, 6) == val)
2527 return;
2528
2529 write_1d0(val, 0x10b, 6, 1);
2530
2531 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2532 u16 reg_500;
2533 reg_500 = read_500(info, channel,
2534 get_timing_register_addr(lane, 0, slot,
2535 rank), 9);
2536 if (val == 1) {
2537 if (lut16[info->clock_speed_index] <= reg_500)
2538 reg_500 -= lut16[info->clock_speed_index];
2539 else
2540 reg_500 = 0;
2541 } else {
2542 reg_500 += lut16[info->clock_speed_index];
2543 }
2544 write_500(info, channel, reg_500,
2545 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2546 }
2547}
2548
2549static void set_ecc(int onoff)
2550{
2551 int channel;
2552 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2553 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002554 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002555 if (onoff)
2556 t |= 1;
2557 else
2558 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002559 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002560 }
2561}
2562
2563static void set_178(u8 val)
2564{
2565 if (val >= 31)
2566 val = val - 31;
2567 else
2568 val = 63 - val;
2569
2570 write_1d0(2 * val, 0x178, 7, 1);
2571}
2572
2573static void
2574write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2575 int type)
2576{
2577 int lane;
2578
2579 for (lane = 0; lane < 8; lane++)
2580 write_500(info, channel,
2581 info->training.
2582 lane_timings[type][channel][slot][rank][lane],
2583 get_timing_register_addr(lane, type, slot, rank), 9,
2584 0);
2585}
2586
2587static void
2588try_timing_offsets(struct raminfo *info, int channel,
2589 int slot, int rank, int totalrank)
2590{
2591 u16 count[8];
2592 enum state state[8];
2593 u8 lower_usable[8], upper_usable[8];
2594 int lane;
2595 int i;
2596 int flip = 1;
2597 int timing_offset;
2598
2599 for (i = 0; i < 8; i++)
2600 state[i] = BEFORE_USABLE;
2601
2602 memset(count, 0, sizeof(count));
2603
2604 for (lane = 0; lane < 8; lane++)
2605 write_500(info, channel,
2606 info->training.
2607 lane_timings[2][channel][slot][rank][lane] + 32,
2608 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2609
2610 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2611 timing_offset++) {
2612 u8 failmask;
2613 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2614 failmask = 0;
2615 for (i = 0; i < 2 && failmask != 0xff; i++) {
2616 flip = !flip;
2617 write_testing(info, totalrank, flip);
2618 failmask |= check_testing(info, totalrank, flip);
2619 }
2620 do_fsm(state, count, failmask, 10, 63, lower_usable,
2621 upper_usable, timing_offset);
2622 }
2623 write_1d0(0, 0x1bb, 6, 1);
2624 dump_timings(info);
2625 if (!validate_state(state))
2626 die("Couldn't discover DRAM timings (1)\n");
2627
2628 for (lane = 0; lane < 8; lane++) {
2629 u8 bias = 0;
2630
2631 if (info->silicon_revision) {
2632 int usable_length;
2633
2634 usable_length = upper_usable[lane] - lower_usable[lane];
2635 if (usable_length >= 20) {
2636 bias = usable_length / 2 - 10;
2637 if (bias >= 2)
2638 bias = 2;
2639 }
2640 }
2641 write_500(info, channel,
2642 info->training.
2643 lane_timings[2][channel][slot][rank][lane] +
2644 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2645 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2646 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2647 info->training.lane_timings[2][channel][slot][rank][lane] +
2648 lower_usable[lane];
2649 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2650 info->training.lane_timings[2][channel][slot][rank][lane] +
2651 upper_usable[lane];
2652 info->training.timing2_offset[channel][slot][rank][lane] =
2653 info->training.lane_timings[2][channel][slot][rank][lane];
2654 }
2655}
2656
2657static u8
2658choose_training(struct raminfo *info, int channel, int slot, int rank,
2659 int lane, timing_bounds_t * timings, u8 center_178)
2660{
2661 u16 central_weight;
2662 u16 side_weight;
2663 unsigned int sum = 0, count = 0;
2664 u8 span;
2665 u8 lower_margin, upper_margin;
2666 u8 reg_178;
2667 u8 result;
2668
2669 span = 12;
2670 central_weight = 20;
2671 side_weight = 20;
2672 if (info->silicon_revision == 1 && channel == 1) {
2673 central_weight = 5;
2674 side_weight = 20;
2675 if ((info->
2676 populated_ranks_mask[1] ^ (info->
2677 populated_ranks_mask[1] >> 2)) &
2678 1)
2679 span = 18;
2680 }
2681 if ((info->populated_ranks_mask[0] & 5) == 5) {
2682 central_weight = 20;
2683 side_weight = 20;
2684 }
2685 if (info->clock_speed_index >= 2
2686 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2687 if (info->silicon_revision == 1) {
2688 switch (channel) {
2689 case 0:
2690 if (lane == 1) {
2691 central_weight = 10;
2692 side_weight = 20;
2693 }
2694 break;
2695 case 1:
2696 if (lane == 6) {
2697 side_weight = 5;
2698 central_weight = 20;
2699 }
2700 break;
2701 }
2702 }
2703 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2704 side_weight = 5;
2705 central_weight = 20;
2706 }
2707 }
2708 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2709 reg_178 += span) {
2710 u8 smallest;
2711 u8 largest;
2712 largest = timings[reg_178][channel][slot][rank][lane].largest;
2713 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2714 if (largest - smallest + 1 >= 5) {
2715 unsigned int weight;
2716 if (reg_178 == center_178)
2717 weight = central_weight;
2718 else
2719 weight = side_weight;
2720 sum += weight * (largest + smallest);
2721 count += weight;
2722 }
2723 }
2724 dump_timings(info);
2725 if (count == 0)
2726 die("Couldn't discover DRAM timings (2)\n");
2727 result = sum / (2 * count);
2728 lower_margin =
2729 result - timings[center_178][channel][slot][rank][lane].smallest;
2730 upper_margin =
2731 timings[center_178][channel][slot][rank][lane].largest - result;
2732 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002733 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002734 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002735 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002736 return result;
2737}
2738
2739#define STANDARD_MIN_MARGIN 5
2740
2741static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2742{
2743 u16 margin[64];
2744 int lane, rank, slot, channel;
2745 u8 reg178;
2746 int count = 0, sum = 0;
2747
2748 for (reg178 = reg178_min[info->clock_speed_index];
2749 reg178 < reg178_max[info->clock_speed_index];
2750 reg178 += reg178_step[info->clock_speed_index]) {
2751 margin[reg178] = -1;
2752 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2753 int curmargin =
2754 timings[reg178][channel][slot][rank][lane].largest -
2755 timings[reg178][channel][slot][rank][lane].
2756 smallest + 1;
2757 if (curmargin < margin[reg178])
2758 margin[reg178] = curmargin;
2759 }
2760 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2761 u16 weight;
2762 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2763 sum += weight * reg178;
2764 count += weight;
2765 }
2766 }
2767 dump_timings(info);
2768 if (count == 0)
2769 die("Couldn't discover DRAM timings (3)\n");
2770
2771 u8 threshold;
2772
2773 for (threshold = 30; threshold >= 5; threshold--) {
2774 int usable_length = 0;
2775 int smallest_fount = 0;
2776 for (reg178 = reg178_min[info->clock_speed_index];
2777 reg178 < reg178_max[info->clock_speed_index];
2778 reg178 += reg178_step[info->clock_speed_index])
2779 if (margin[reg178] >= threshold) {
2780 usable_length +=
2781 reg178_step[info->clock_speed_index];
2782 info->training.reg178_largest =
2783 reg178 -
2784 2 * reg178_step[info->clock_speed_index];
2785
2786 if (!smallest_fount) {
2787 smallest_fount = 1;
2788 info->training.reg178_smallest =
2789 reg178 +
2790 reg178_step[info->
2791 clock_speed_index];
2792 }
2793 }
2794 if (usable_length >= 0x21)
2795 break;
2796 }
2797
2798 return sum / count;
2799}
2800
2801static int check_cached_sanity(struct raminfo *info)
2802{
2803 int lane;
2804 int slot, rank;
2805 int channel;
2806
2807 if (!info->cached_training)
2808 return 0;
2809
2810 for (channel = 0; channel < NUM_CHANNELS; channel++)
2811 for (slot = 0; slot < NUM_SLOTS; slot++)
2812 for (rank = 0; rank < NUM_RANKS; rank++)
2813 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2814 u16 cached_value, estimation_value;
2815 cached_value =
2816 info->cached_training->
2817 lane_timings[1][channel][slot][rank]
2818 [lane];
2819 if (cached_value >= 0x18
2820 && cached_value <= 0x1E7) {
2821 estimation_value =
2822 info->training.
2823 lane_timings[1][channel]
2824 [slot][rank][lane];
2825 if (estimation_value <
2826 cached_value - 24)
2827 return 0;
2828 if (estimation_value >
2829 cached_value + 24)
2830 return 0;
2831 }
2832 }
2833 return 1;
2834}
2835
2836static int try_cached_training(struct raminfo *info)
2837{
2838 u8 saved_243[2];
2839 u8 tm;
2840
2841 int channel, slot, rank, lane;
2842 int flip = 1;
2843 int i, j;
2844
2845 if (!check_cached_sanity(info))
2846 return 0;
2847
2848 info->training.reg178_center = info->cached_training->reg178_center;
2849 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2850 info->training.reg178_largest = info->cached_training->reg178_largest;
2851 memcpy(&info->training.timing_bounds,
2852 &info->cached_training->timing_bounds,
2853 sizeof(info->training.timing_bounds));
2854 memcpy(&info->training.timing_offset,
2855 &info->cached_training->timing_offset,
2856 sizeof(info->training.timing_offset));
2857
2858 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002859 saved_243[0] = MCHBAR8(0x243);
2860 saved_243[1] = MCHBAR8(0x643);
2861 MCHBAR8(0x243) = saved_243[0] | 2;
2862 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002863 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002864 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002865 if (read_1d0(0x10b, 6) & 1)
2866 set_10b(info, 0);
2867 for (tm = 0; tm < 2; tm++) {
2868 int totalrank;
2869
2870 set_178(tm ? info->cached_training->reg178_largest : info->
2871 cached_training->reg178_smallest);
2872
2873 totalrank = 0;
2874 /* Check timing ranges. With i == 0 we check smallest one and with
2875 i == 1 the largest bound. With j == 0 we check that on the bound
2876 it still works whereas with j == 1 we check that just outside of
2877 bound we fail.
2878 */
2879 FOR_POPULATED_RANKS_BACKWARDS {
2880 for (i = 0; i < 2; i++) {
2881 for (lane = 0; lane < 8; lane++) {
2882 write_500(info, channel,
2883 info->cached_training->
2884 timing2_bounds[channel][slot]
2885 [rank][lane][i],
2886 get_timing_register_addr(lane,
2887 3,
2888 slot,
2889 rank),
2890 9, 1);
2891
2892 if (!i)
2893 write_500(info, channel,
2894 info->
2895 cached_training->
2896 timing2_offset
2897 [channel][slot][rank]
2898 [lane],
2899 get_timing_register_addr
2900 (lane, 2, slot, rank),
2901 9, 1);
2902 write_500(info, channel,
2903 i ? info->cached_training->
2904 timing_bounds[tm][channel]
2905 [slot][rank][lane].
2906 largest : info->
2907 cached_training->
2908 timing_bounds[tm][channel]
2909 [slot][rank][lane].smallest,
2910 get_timing_register_addr(lane,
2911 0,
2912 slot,
2913 rank),
2914 9, 1);
2915 write_500(info, channel,
2916 info->cached_training->
2917 timing_offset[channel][slot]
2918 [rank][lane] +
2919 (i ? info->cached_training->
2920 timing_bounds[tm][channel]
2921 [slot][rank][lane].
2922 largest : info->
2923 cached_training->
2924 timing_bounds[tm][channel]
2925 [slot][rank][lane].
2926 smallest) - 64,
2927 get_timing_register_addr(lane,
2928 1,
2929 slot,
2930 rank),
2931 9, 1);
2932 }
2933 for (j = 0; j < 2; j++) {
2934 u8 failmask;
2935 u8 expected_failmask;
2936 char reg1b3;
2937
2938 reg1b3 = (j == 1) + 4;
2939 reg1b3 =
2940 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2941 write_1d0(reg1b3, 0x1bb, 6, 1);
2942 write_1d0(reg1b3, 0x1b3, 6, 1);
2943 write_1d0(reg1b3, 0x1a3, 6, 1);
2944
2945 flip = !flip;
2946 write_testing(info, totalrank, flip);
2947 failmask =
2948 check_testing(info, totalrank,
2949 flip);
2950 expected_failmask =
2951 j == 0 ? 0x00 : 0xff;
2952 if (failmask != expected_failmask)
2953 goto fail;
2954 }
2955 }
2956 totalrank++;
2957 }
2958 }
2959
2960 set_178(info->cached_training->reg178_center);
2961 if (info->use_ecc)
2962 set_ecc(1);
2963 write_training_data(info);
2964 write_1d0(0, 322, 3, 1);
2965 info->training = *info->cached_training;
2966
2967 write_1d0(0, 0x1bb, 6, 1);
2968 write_1d0(0, 0x1b3, 6, 1);
2969 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002970 MCHBAR8(0x243) = saved_243[0];
2971 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002972
2973 return 1;
2974
2975fail:
2976 FOR_POPULATED_RANKS {
2977 write_500_timings_type(info, channel, slot, rank, 1);
2978 write_500_timings_type(info, channel, slot, rank, 2);
2979 write_500_timings_type(info, channel, slot, rank, 3);
2980 }
2981
2982 write_1d0(0, 0x1bb, 6, 1);
2983 write_1d0(0, 0x1b3, 6, 1);
2984 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002985 MCHBAR8(0x243) = saved_243[0];
2986 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002987
2988 return 0;
2989}
2990
2991static void do_ram_training(struct raminfo *info)
2992{
2993 u8 saved_243[2];
2994 int totalrank = 0;
2995 u8 reg_178;
2996 int niter;
2997
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002998 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002999 int lane, rank, slot, channel;
3000 u8 reg178_center;
3001
3002 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003003 saved_243[0] = MCHBAR8(0x243);
3004 saved_243[1] = MCHBAR8(0x643);
3005 MCHBAR8(0x243) = saved_243[0] | 2;
3006 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003007 switch (info->clock_speed_index) {
3008 case 0:
3009 niter = 5;
3010 break;
3011 case 1:
3012 niter = 10;
3013 break;
3014 default:
3015 niter = 19;
3016 break;
3017 }
3018 set_ecc(0);
3019
3020 FOR_POPULATED_RANKS_BACKWARDS {
3021 int i;
3022
3023 write_500_timings_type(info, channel, slot, rank, 0);
3024
3025 write_testing(info, totalrank, 0);
3026 for (i = 0; i < niter; i++) {
3027 write_testing_type2(info, totalrank, 2, i, 0);
3028 write_testing_type2(info, totalrank, 3, i, 1);
3029 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003030 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003031 totalrank++;
3032 }
3033
3034 if (reg178_min[info->clock_speed_index] <
3035 reg178_max[info->clock_speed_index])
3036 memset(timings[reg178_min[info->clock_speed_index]], 0,
3037 sizeof(timings[0]) *
3038 (reg178_max[info->clock_speed_index] -
3039 reg178_min[info->clock_speed_index]));
3040 for (reg_178 = reg178_min[info->clock_speed_index];
3041 reg_178 < reg178_max[info->clock_speed_index];
3042 reg_178 += reg178_step[info->clock_speed_index]) {
3043 totalrank = 0;
3044 set_178(reg_178);
3045 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3046 for (slot = 0; slot < NUM_SLOTS; slot++)
3047 for (rank = 0; rank < NUM_RANKS; rank++) {
3048 memset(&timings[reg_178][channel][slot]
3049 [rank][0].smallest, 0, 16);
3050 if (info->
3051 populated_ranks[channel][slot]
3052 [rank]) {
3053 train_ram_at_178(info, channel,
3054 slot, rank,
3055 totalrank,
3056 reg_178, 1,
3057 niter,
3058 timings);
3059 totalrank++;
3060 }
3061 }
3062 }
3063
3064 reg178_center = choose_reg178(info, timings);
3065
3066 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3067 info->training.timing_bounds[0][channel][slot][rank][lane].
3068 smallest =
3069 timings[info->training.
3070 reg178_smallest][channel][slot][rank][lane].
3071 smallest;
3072 info->training.timing_bounds[0][channel][slot][rank][lane].
3073 largest =
3074 timings[info->training.
3075 reg178_smallest][channel][slot][rank][lane].largest;
3076 info->training.timing_bounds[1][channel][slot][rank][lane].
3077 smallest =
3078 timings[info->training.
3079 reg178_largest][channel][slot][rank][lane].smallest;
3080 info->training.timing_bounds[1][channel][slot][rank][lane].
3081 largest =
3082 timings[info->training.
3083 reg178_largest][channel][slot][rank][lane].largest;
3084 info->training.timing_offset[channel][slot][rank][lane] =
3085 info->training.lane_timings[1][channel][slot][rank][lane]
3086 -
3087 info->training.lane_timings[0][channel][slot][rank][lane] +
3088 64;
3089 }
3090
3091 if (info->silicon_revision == 1
3092 && (info->
3093 populated_ranks_mask[1] ^ (info->
3094 populated_ranks_mask[1] >> 2)) & 1) {
3095 int ranks_after_channel1;
3096
3097 totalrank = 0;
3098 for (reg_178 = reg178_center - 18;
3099 reg_178 <= reg178_center + 18; reg_178 += 18) {
3100 totalrank = 0;
3101 set_178(reg_178);
3102 for (slot = 0; slot < NUM_SLOTS; slot++)
3103 for (rank = 0; rank < NUM_RANKS; rank++) {
3104 if (info->
3105 populated_ranks[1][slot][rank]) {
3106 train_ram_at_178(info, 1, slot,
3107 rank,
3108 totalrank,
3109 reg_178, 0,
3110 niter,
3111 timings);
3112 totalrank++;
3113 }
3114 }
3115 }
3116 ranks_after_channel1 = totalrank;
3117
3118 for (reg_178 = reg178_center - 12;
3119 reg_178 <= reg178_center + 12; reg_178 += 12) {
3120 totalrank = ranks_after_channel1;
3121 set_178(reg_178);
3122 for (slot = 0; slot < NUM_SLOTS; slot++)
3123 for (rank = 0; rank < NUM_RANKS; rank++)
3124 if (info->
3125 populated_ranks[0][slot][rank]) {
3126 train_ram_at_178(info, 0, slot,
3127 rank,
3128 totalrank,
3129 reg_178, 0,
3130 niter,
3131 timings);
3132 totalrank++;
3133 }
3134
3135 }
3136 } else {
3137 for (reg_178 = reg178_center - 12;
3138 reg_178 <= reg178_center + 12; reg_178 += 12) {
3139 totalrank = 0;
3140 set_178(reg_178);
3141 FOR_POPULATED_RANKS_BACKWARDS {
3142 train_ram_at_178(info, channel, slot, rank,
3143 totalrank, reg_178, 0, niter,
3144 timings);
3145 totalrank++;
3146 }
3147 }
3148 }
3149
3150 set_178(reg178_center);
3151 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3152 u16 tm0;
3153
3154 tm0 =
3155 choose_training(info, channel, slot, rank, lane, timings,
3156 reg178_center);
3157 write_500(info, channel, tm0,
3158 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3159 write_500(info, channel,
3160 tm0 +
3161 info->training.
3162 lane_timings[1][channel][slot][rank][lane] -
3163 info->training.
3164 lane_timings[0][channel][slot][rank][lane],
3165 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3166 }
3167
3168 totalrank = 0;
3169 FOR_POPULATED_RANKS_BACKWARDS {
3170 try_timing_offsets(info, channel, slot, rank, totalrank);
3171 totalrank++;
3172 }
Felix Held04be2dd2018-07-29 04:53:22 +02003173 MCHBAR8(0x243) = saved_243[0];
3174 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003175 write_1d0(0, 0x142, 3, 1);
3176 info->training.reg178_center = reg178_center;
3177}
3178
3179static void ram_training(struct raminfo *info)
3180{
3181 u16 saved_fc4;
3182
Felix Held04be2dd2018-07-29 04:53:22 +02003183 saved_fc4 = MCHBAR16(0xfc4);
3184 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003185
3186 if (info->revision >= 8)
3187 read_4090(info);
3188
3189 if (!try_cached_training(info))
3190 do_ram_training(info);
3191 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3192 && info->clock_speed_index < 2)
3193 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003194 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195}
3196
Martin Roth468d02c2019-10-23 21:44:42 -06003197static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003198{
Martin Roth468d02c2019-10-23 21:44:42 -06003199 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003200 if (a > b) {
3201 t = a;
3202 a = b;
3203 b = t;
3204 }
3205 /* invariant a < b. */
3206 while (a) {
3207 t = b % a;
3208 b = a;
3209 a = t;
3210 }
3211 return b;
3212}
3213
3214static inline int div_roundup(int a, int b)
3215{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003216 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003217}
3218
Martin Roth468d02c2019-10-23 21:44:42 -06003219static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003220{
3221 return (a * b) / gcd(a, b);
3222}
3223
3224struct stru1 {
3225 u8 freqs_reversed;
3226 u8 freq_diff_reduced;
3227 u8 freq_min_reduced;
3228 u8 divisor_f4_to_fmax;
3229 u8 divisor_f3_to_fmax;
3230 u8 freq4_to_max_remainder;
3231 u8 freq3_to_2_remainder;
3232 u8 freq3_to_2_remaindera;
3233 u8 freq4_to_2_remainder;
3234 int divisor_f3_to_f1, divisor_f4_to_f2;
3235 int common_time_unit_ps;
3236 int freq_max_reduced;
3237};
3238
3239static void
3240compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3241 int num_cycles_2, int num_cycles_1, int round_it,
3242 int add_freqs, struct stru1 *result)
3243{
3244 int g;
3245 int common_time_unit_ps;
3246 int freq1_reduced, freq2_reduced;
3247 int freq_min_reduced;
3248 int freq_max_reduced;
3249 int freq3, freq4;
3250
3251 g = gcd(freq1, freq2);
3252 freq1_reduced = freq1 / g;
3253 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003254 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3255 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003256
3257 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3258 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3259 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3260 if (add_freqs) {
3261 freq3 += freq2_reduced;
3262 freq4 += freq1_reduced;
3263 }
3264
3265 if (round_it) {
3266 result->freq3_to_2_remainder = 0;
3267 result->freq3_to_2_remaindera = 0;
3268 result->freq4_to_max_remainder = 0;
3269 result->divisor_f4_to_f2 = 0;
3270 result->divisor_f3_to_f1 = 0;
3271 } else {
3272 if (freq2_reduced < freq1_reduced) {
3273 result->freq3_to_2_remainder =
3274 result->freq3_to_2_remaindera =
3275 freq3 % freq1_reduced - freq1_reduced + 1;
3276 result->freq4_to_max_remainder =
3277 -(freq4 % freq1_reduced);
3278 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3279 result->divisor_f4_to_f2 =
3280 (freq4 -
3281 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3282 result->freq4_to_2_remainder =
3283 -(char)((freq1_reduced - freq2_reduced) +
3284 ((u8) freq4 -
3285 (freq1_reduced -
3286 freq2_reduced)) % (u8) freq2_reduced);
3287 } else {
3288 if (freq2_reduced > freq1_reduced) {
3289 result->freq4_to_max_remainder =
3290 (freq4 % freq2_reduced) - freq2_reduced + 1;
3291 result->freq4_to_2_remainder =
3292 freq4 % freq_max_reduced -
3293 freq_max_reduced + 1;
3294 } else {
3295 result->freq4_to_max_remainder =
3296 -(freq4 % freq2_reduced);
3297 result->freq4_to_2_remainder =
3298 -(char)(freq4 % freq_max_reduced);
3299 }
3300 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3301 result->divisor_f3_to_f1 =
3302 (freq3 -
3303 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3304 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3305 result->freq3_to_2_remaindera =
3306 -(char)((freq_max_reduced - freq_min_reduced) +
3307 (freq3 -
3308 (freq_max_reduced -
3309 freq_min_reduced)) % freq1_reduced);
3310 }
3311 }
3312 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3313 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3314 if (round_it) {
3315 if (freq2_reduced > freq1_reduced) {
3316 if (freq3 % freq_max_reduced)
3317 result->divisor_f3_to_fmax++;
3318 }
3319 if (freq2_reduced < freq1_reduced) {
3320 if (freq4 % freq_max_reduced)
3321 result->divisor_f4_to_fmax++;
3322 }
3323 }
3324 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3325 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3326 result->freq_min_reduced = freq_min_reduced;
3327 result->common_time_unit_ps = common_time_unit_ps;
3328 result->freq_max_reduced = freq_max_reduced;
3329}
3330
3331static void
3332set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3333 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3334 int num_cycles_4, int reverse)
3335{
3336 struct stru1 vv;
3337 char multiplier;
3338
3339 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3340 0, 1, &vv);
3341
3342 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003343 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003344 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3345 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3346 div_roundup(num_cycles_1,
3347 vv.common_time_unit_ps) +
3348 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3349 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3350
3351 u32 y =
3352 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3353 vv.freq_max_reduced * multiplier)
3354 | (vv.
3355 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3356 multiplier) << 16) | ((u8) (vv.
3357 freq_min_reduced
3358 *
3359 multiplier)
3360 << 24);
3361 u32 x =
3362 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3363 divisor_f3_to_f1
3364 << 16)
3365 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3366 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003367 MCHBAR32(reg) = y;
3368 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003369 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003370 MCHBAR32(reg + 4) = y;
3371 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003372 }
3373}
3374
3375static void
3376set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3377 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3378 int num_cycles_4)
3379{
3380 struct stru1 ratios1;
3381 struct stru1 ratios2;
3382
3383 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3384 0, 1, &ratios2);
3385 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3386 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003387 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003388 ratios1.freq4_to_max_remainder | (ratios2.
3389 freq4_to_max_remainder
3390 << 8)
3391 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3392 divisor_f4_to_fmax
3393 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003394 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3395 (ratios2.freq4_to_max_remainder << 8) |
3396 (ratios1.divisor_f4_to_fmax << 16) |
3397 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003398}
3399
3400static void
3401set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3402 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3403{
3404 struct stru1 ratios;
3405
3406 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3407 round_it, add_freqs, &ratios);
3408 switch (mode) {
3409 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003410 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3411 (ratios.freqs_reversed << 8);
3412 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3413 (ratios.freq4_to_max_remainder << 8) |
3414 (ratios.divisor_f3_to_fmax << 16) |
3415 (ratios.divisor_f4_to_fmax << 20) |
3416 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003417 break;
3418
3419 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003420 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3421 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003422 break;
3423
3424 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003425 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3426 (ratios.freq4_to_max_remainder << 8) |
3427 (ratios.divisor_f3_to_fmax << 16) |
3428 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003429 break;
3430
3431 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003432 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3433 (ratios.divisor_f4_to_fmax << 8) |
3434 (ratios.freqs_reversed << 12) |
3435 (ratios.freq_min_reduced << 16) |
3436 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003437 break;
3438 }
3439}
3440
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003441static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003442{
3443 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3444 0, 1);
3445 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3446 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3447 1);
3448 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3449 frequency_11(info), 1231, 1524, 0, 1);
3450 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3451 frequency_11(info) / 2, 1278, 2008, 0, 1);
3452 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3453 1167, 1539, 0, 1);
3454 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3455 frequency_11(info) / 2, 1403, 1318, 0, 1);
3456 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3457 1);
3458 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3459 1);
3460 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3461 1, 1);
3462 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3463 1);
3464 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3465 frequency_11(info) / 2, 4000, 0, 0, 0);
3466 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3467 frequency_11(info) / 2, 4000, 4000, 0, 0);
3468
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003469 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003470 printk(RAM_SPEW, "[6dc] <= %x\n",
3471 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003472 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003473 } else
3474 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3475 info->delay46_ps[0], 0,
3476 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3478 frequency_11(info), 2500, 0, 0, 0);
3479 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3480 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003481 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003482 printk(RAM_SPEW, "[6e8] <= %x\n",
3483 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003484 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003485 } else
3486 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3487 info->delay46_ps[1], 0,
3488 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003489 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3490 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3491 470, 0);
3492 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3493 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3494 454, 459, 0);
3495 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3496 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3497 2588, 0);
3498 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3499 2405, 0);
3500 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3501 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3502 480, 0);
3503 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003504 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3505 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003506}
3507
3508static u16 get_max_timing(struct raminfo *info, int channel)
3509{
3510 int slot, rank, lane;
3511 u16 ret = 0;
3512
Felix Held04be2dd2018-07-29 04:53:22 +02003513 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514 return 384;
3515
3516 if (info->revision < 8)
3517 return 256;
3518
3519 for (slot = 0; slot < NUM_SLOTS; slot++)
3520 for (rank = 0; rank < NUM_RANKS; rank++)
3521 if (info->populated_ranks[channel][slot][rank])
3522 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003523 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003524 get_timing_register_addr
3525 (lane, 0, slot,
3526 rank), 9));
3527 return ret;
3528}
3529
3530static void set_274265(struct raminfo *info)
3531{
3532 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3533 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3534 int delay_e_over_cycle_ps;
3535 int cycletime_ps;
3536 int channel;
3537
3538 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003539 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003540 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3541 cycletime_ps =
3542 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3543 delay_d_ps =
3544 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3545 - info->some_delay_3_ps_rounded + 200;
3546 if (!
3547 ((info->silicon_revision == 0
3548 || info->silicon_revision == 1)
3549 && (info->revision >= 8)))
3550 delay_d_ps += halfcycle_ps(info) * 2;
3551 delay_d_ps +=
3552 halfcycle_ps(info) * (!info->revision_flag_1 +
3553 info->some_delay_2_halfcycles_ceil +
3554 2 * info->some_delay_1_cycle_floor +
3555 info->clock_speed_index +
3556 2 * info->cas_latency - 7 + 11);
3557 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3558
Felix Held04be2dd2018-07-29 04:53:22 +02003559 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3560 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3561 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003562 delay_d_ps += 650;
3563 delay_c_ps = delay_d_ps + 1800;
3564 if (delay_c_ps <= delay_a_ps)
3565 delay_e_ps = 0;
3566 else
3567 delay_e_ps =
3568 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3569 cycletime_ps);
3570
3571 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3572 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3573 delay_f_cycles =
3574 div_roundup(2500 - delay_e_over_cycle_ps,
3575 2 * halfcycle_ps(info));
3576 if (delay_f_cycles > delay_e_cycles) {
3577 info->delay46_ps[channel] = delay_e_ps;
3578 delay_e_cycles = 0;
3579 } else {
3580 info->delay46_ps[channel] =
3581 delay_e_over_cycle_ps +
3582 2 * halfcycle_ps(info) * delay_f_cycles;
3583 delay_e_cycles -= delay_f_cycles;
3584 }
3585
3586 if (info->delay46_ps[channel] < 2500) {
3587 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003588 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003589 }
3590 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3591 if (delay_b_ps <= delay_a_ps)
3592 delay_b_ps = 0;
3593 else
3594 delay_b_ps -= delay_a_ps;
3595 info->delay54_ps[channel] =
3596 cycletime_ps * div_roundup(delay_b_ps,
3597 cycletime_ps) -
3598 2 * halfcycle_ps(info) * delay_e_cycles;
3599 if (info->delay54_ps[channel] < 2500)
3600 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003601 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003602 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3603 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003604 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003606 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003607 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3608 4 * halfcycle_ps(info)) - 6;
3609 MCHBAR32((channel << 10) + 0x274) =
3610 info->training.reg274265[channel][1] |
3611 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003612 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003613 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3614 4 * halfcycle_ps(info)) + 1;
3615 MCHBAR16((channel << 10) + 0x265) =
3616 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003618 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003619 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620 else
Felix Held04be2dd2018-07-29 04:53:22 +02003621 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622}
3623
3624static void restore_274265(struct raminfo *info)
3625{
3626 int channel;
3627
3628 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003629 MCHBAR32((channel << 10) + 0x274) =
3630 (info->cached_training->reg274265[channel][0] << 16) |
3631 info->cached_training->reg274265[channel][1];
3632 MCHBAR16((channel << 10) + 0x265) =
3633 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003635 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003636 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637 else
Felix Held04be2dd2018-07-29 04:53:22 +02003638 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639}
3640
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003641static void dmi_setup(void)
3642{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003643 gav(read8(DEFAULT_DMIBAR + 0x254));
3644 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3645 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003646 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003648 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649
3650 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3651 DEFAULT_GPIOBASE | 0x38);
3652 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3653}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003655void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003658 u16 ggc;
3659 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003660
Felix Held04be2dd2018-07-29 04:53:22 +02003661 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3663 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003665 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666 }
Felix Held29a9c072018-07-29 01:34:45 +02003667#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668 if (!s3resume) {
3669 pre_raminit_3(x2ca8);
3670 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003671 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672#endif
3673
3674 dmi_setup();
3675
Felix Held04be2dd2018-07-29 04:53:22 +02003676 MCHBAR16(0x1170) = 0xa880;
3677 MCHBAR8(0x11c1) = 0x1;
3678 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003679 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003681 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3682 /* 0 for 32MB */
3683 gfxsize = 0;
3684 }
3685
3686 ggc = 0xb00 | ((gfxsize + 5) << 4);
3687
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003688 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689
3690 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003691 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003692
3693 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003694 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003695 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003696 MCHBAR16_OR(0x2c30, 0x200);
3697 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003698 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003699 pci_read_config8(GMA, 0x62); // = 0x2
3700 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003701 read8(DEFAULT_RCBA + 0x2318);
3702 write8(DEFAULT_RCBA + 0x2318, 0x47);
3703 read8(DEFAULT_RCBA + 0x2320);
3704 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003705 }
3706
Felix Heldf83d80b2018-07-29 05:30:30 +02003707 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003708
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003709 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003710 gav(read32(DEFAULT_RCBA + 0x3428));
3711 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003712}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003714void raminit(const int s3resume, const u8 *spd_addrmap)
3715{
Martin Roth468d02c2019-10-23 21:44:42 -06003716 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003717 int i;
3718 struct raminfo info;
3719 u8 x2ca8;
3720 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003721 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003722
Felix Held04be2dd2018-07-29 04:53:22 +02003723 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003724
3725 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3726
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003727 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728
3729 memset(&info, 0x5a, sizeof(info));
3730
3731 info.last_500_command[0] = 0;
3732 info.last_500_command[1] = 0;
3733
3734 info.fsb_frequency = 135 * 2;
3735 info.board_lane_delay[0] = 0x14;
3736 info.board_lane_delay[1] = 0x07;
3737 info.board_lane_delay[2] = 0x07;
3738 info.board_lane_delay[3] = 0x08;
3739 info.board_lane_delay[4] = 0x56;
3740 info.board_lane_delay[5] = 0x04;
3741 info.board_lane_delay[6] = 0x04;
3742 info.board_lane_delay[7] = 0x05;
3743 info.board_lane_delay[8] = 0x10;
3744
3745 info.training.reg_178 = 0;
3746 info.training.reg_10b = 0;
3747
3748 info.heci_bar = 0;
3749 info.memory_reserved_for_heci_mb = 0;
3750
3751 /* before SPD */
3752 timestamp_add_now(101);
3753
Felix Held29a9c072018-07-29 01:34:45 +02003754 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003755 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003756
3757 collect_system_info(&info);
3758
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003759 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3760
3761 info.use_ecc = 1;
3762 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003763 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764 int v;
3765 int try;
3766 int addr;
3767 const u8 useful_addresses[] = {
3768 DEVICE_TYPE,
3769 MODULE_TYPE,
3770 DENSITY,
3771 RANKS_AND_DQ,
3772 MEMORY_BUS_WIDTH,
3773 TIMEBASE_DIVIDEND,
3774 TIMEBASE_DIVISOR,
3775 CYCLETIME,
3776 CAS_LATENCIES_LSB,
3777 CAS_LATENCIES_MSB,
3778 CAS_LATENCY_TIME,
3779 0x11, 0x12, 0x13, 0x14, 0x15,
3780 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3781 0x1c, 0x1d,
3782 THERMAL_AND_REFRESH,
3783 0x20,
3784 REFERENCE_RAW_CARD_USED,
3785 RANK1_ADDRESS_MAPPING,
3786 0x75, 0x76, 0x77, 0x78,
3787 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3788 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3789 0x85, 0x86, 0x87, 0x88,
3790 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3791 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3792 0x95
3793 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003794 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003795 continue;
3796 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003797 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003798 DEVICE_TYPE);
3799 if (v >= 0)
3800 break;
3801 }
3802 if (v < 0)
3803 continue;
3804 for (addr = 0;
3805 addr <
3806 sizeof(useful_addresses) /
3807 sizeof(useful_addresses[0]); addr++)
3808 gav(info.
3809 spd[channel][0][useful_addresses
3810 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003811 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003812 useful_addresses
3813 [addr]));
3814 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3815 die("Only DDR3 is supported");
3816
3817 v = info.spd[channel][0][RANKS_AND_DQ];
3818 info.populated_ranks[channel][0][0] = 1;
3819 info.populated_ranks[channel][0][1] =
3820 ((v >> 3) & 7);
3821 if (((v >> 3) & 7) > 1)
3822 die("At most 2 ranks are supported");
3823 if ((v & 7) == 0 || (v & 7) > 2)
3824 die("Only x8 and x16 modules are supported");
3825 if ((info.
3826 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3827 && (info.
3828 spd[channel][slot][MODULE_TYPE] & 0xF)
3829 != 3)
3830 die("Registered memory is not supported");
3831 info.is_x16_module[channel][0] = (v & 7) - 1;
3832 info.density[channel][slot] =
3833 info.spd[channel][slot][DENSITY] & 0xF;
3834 if (!
3835 (info.
3836 spd[channel][slot][MEMORY_BUS_WIDTH] &
3837 0x18))
3838 info.use_ecc = 0;
3839 }
3840
3841 gav(0x55);
3842
3843 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3844 int v = 0;
3845 for (slot = 0; slot < NUM_SLOTS; slot++)
3846 for (rank = 0; rank < NUM_RANKS; rank++)
3847 v |= info.
3848 populated_ranks[channel][slot][rank]
3849 << (2 * slot + rank);
3850 info.populated_ranks_mask[channel] = v;
3851 }
3852
3853 gav(0x55);
3854
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003855 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003856 }
3857
3858 /* after SPD */
3859 timestamp_add_now(102);
3860
Felix Held04be2dd2018-07-29 04:53:22 +02003861 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862
3863 collect_system_info(&info);
3864 calculate_timings(&info);
3865
Felix Held29a9c072018-07-29 01:34:45 +02003866#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003867 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868#endif
3869
3870 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003871 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872 if (x2ca8 == 0 && (reg8 & 0x80)) {
3873 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3874 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3875 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3876 */
3877
3878 /* Clear bit7. */
3879
3880 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3881 (reg8 & ~(1 << 7)));
3882
3883 printk(BIOS_INFO,
3884 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003885 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003886 }
3887 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003888
3889 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003890 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3891 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
3893 compute_derived_timings(&info);
3894
3895 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003896 gav(MCHBAR8(0x164));
3897 MCHBAR8(0x164) = 0x26;
3898 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003899 }
3900
Felix Held04be2dd2018-07-29 04:53:22 +02003901 MCHBAR32_OR(0x18b4, 0x210000);
3902 MCHBAR32_OR(0x1890, 0x2000000);
3903 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003904
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003905 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3906 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003907
Felix Held04be2dd2018-07-29 04:53:22 +02003908 gav(MCHBAR16(0x2c10));
3909 MCHBAR16(0x2c10) = 0x412;
3910 gav(MCHBAR16(0x2c10));
3911 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
Felix Held04be2dd2018-07-29 04:53:22 +02003913 gav(MCHBAR8(0x2ca8)); // !!!!
3914 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003915
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003916 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3917 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003918 gav(MCHBAR32(0x1c04)); // !!!!
3919 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
3921 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003922 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003923 }
3924
Felix Held04be2dd2018-07-29 04:53:22 +02003925 MCHBAR32(0x18d8) = 0x120000;
3926 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003927 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3928 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003929 MCHBAR32(0x18d8) = 0x40000;
3930 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003931 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3932 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003933 MCHBAR32(0x18d8) = 0x180000;
3934 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003935 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3936 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003938
Felix Held04be2dd2018-07-29 04:53:22 +02003939 gav(MCHBAR32(0x18dc)); // !!!!
3940 MCHBAR32(0x18dc) = 0x3;
3941 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003942
3943 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003944 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945 }
3946
Felix Held04be2dd2018-07-29 04:53:22 +02003947 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003948 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR32(0x1a10) = 0x4200010e;
3950 MCHBAR32_OR(0x18b8, 0x200);
3951 gav(MCHBAR32(0x1918)); // !!!!
3952 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003953
Felix Held04be2dd2018-07-29 04:53:22 +02003954 gav(MCHBAR32(0x18b8)); // !!!!
3955 MCHBAR32(0x18b8) = 0xe00;
3956 gav(MCHBAR32(0x182c)); // !!!!
3957 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003958 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3959 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003960 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3961 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003962
Felix Held04be2dd2018-07-29 04:53:22 +02003963 MCHBAR32_AND(0x18b4, 0xffff7fff);
3964 gav(MCHBAR32(0x1a68)); // !!!!
3965 MCHBAR32(0x1a68) = 0x343800;
3966 gav(MCHBAR32(0x1e68)); // !!!!
3967 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003968
3969 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003970 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003971 }
3972
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003973 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3974 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3975 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3976 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3977 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3978 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3979 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003980 gav(MCHBAR32(0x1af0)); // !!!!
3981 gav(MCHBAR32(0x1af0)); // !!!!
3982 MCHBAR32(0x1af0) = 0x1f020003;
3983 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003985 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003986 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003987 }
3988
Felix Held04be2dd2018-07-29 04:53:22 +02003989 gav(MCHBAR32(0x1890)); // !!!!
3990 MCHBAR32(0x1890) = 0x80102;
3991 gav(MCHBAR32(0x18b4)); // !!!!
3992 MCHBAR32(0x18b4) = 0x216000;
3993 MCHBAR32(0x18a4) = 0x22222222;
3994 MCHBAR32(0x18a8) = 0x22222222;
3995 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003996
3997 udelay(1000);
3998
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003999 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004000
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004001 if (x2ca8 == 0) {
4002 int j;
4003 if (s3resume && info.cached_training) {
4004 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004005 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004006 info.cached_training->reg2ca9_bit0);
4007 for (i = 0; i < 2; i++)
4008 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004009 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004010 i, j, info.cached_training->reg274265[i][j]);
4011 } else {
4012 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004013 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004014 info.training.reg2ca9_bit0);
4015 for (i = 0; i < 2; i++)
4016 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004017 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004018 i, j, info.training.reg274265[i][j]);
4019 }
4020
4021 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004022
4023 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004024 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004025 }
4026
4027 udelay(1000);
4028
4029 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004030 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004031 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004032 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4033 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4034 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004035
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004036 MCHBAR8(0x1150);
4037 MCHBAR8(0x1151);
4038 MCHBAR8(0x1022);
4039 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004040 MCHBAR32(0x1300) = 0x60606060;
4041 MCHBAR32(0x1304) = 0x60606060;
4042 MCHBAR32(0x1308) = 0x78797a7b;
4043 MCHBAR32(0x130c) = 0x7c7d7e7f;
4044 MCHBAR32(0x1310) = 0x60606060;
4045 MCHBAR32(0x1314) = 0x60606060;
4046 MCHBAR32(0x1318) = 0x60606060;
4047 MCHBAR32(0x131c) = 0x60606060;
4048 MCHBAR32(0x1320) = 0x50515253;
4049 MCHBAR32(0x1324) = 0x54555657;
4050 MCHBAR32(0x1328) = 0x58595a5b;
4051 MCHBAR32(0x132c) = 0x5c5d5e5f;
4052 MCHBAR32(0x1330) = 0x40414243;
4053 MCHBAR32(0x1334) = 0x44454647;
4054 MCHBAR32(0x1338) = 0x48494a4b;
4055 MCHBAR32(0x133c) = 0x4c4d4e4f;
4056 MCHBAR32(0x1340) = 0x30313233;
4057 MCHBAR32(0x1344) = 0x34353637;
4058 MCHBAR32(0x1348) = 0x38393a3b;
4059 MCHBAR32(0x134c) = 0x3c3d3e3f;
4060 MCHBAR32(0x1350) = 0x20212223;
4061 MCHBAR32(0x1354) = 0x24252627;
4062 MCHBAR32(0x1358) = 0x28292a2b;
4063 MCHBAR32(0x135c) = 0x2c2d2e2f;
4064 MCHBAR32(0x1360) = 0x10111213;
4065 MCHBAR32(0x1364) = 0x14151617;
4066 MCHBAR32(0x1368) = 0x18191a1b;
4067 MCHBAR32(0x136c) = 0x1c1d1e1f;
4068 MCHBAR32(0x1370) = 0x10203;
4069 MCHBAR32(0x1374) = 0x4050607;
4070 MCHBAR32(0x1378) = 0x8090a0b;
4071 MCHBAR32(0x137c) = 0xc0d0e0f;
4072 MCHBAR8(0x11cc) = 0x4e;
4073 MCHBAR32(0x1110) = 0x73970404;
4074 MCHBAR32(0x1114) = 0x72960404;
4075 MCHBAR32(0x1118) = 0x6f950404;
4076 MCHBAR32(0x111c) = 0x6d940404;
4077 MCHBAR32(0x1120) = 0x6a930404;
4078 MCHBAR32(0x1124) = 0x68a41404;
4079 MCHBAR32(0x1128) = 0x66a21404;
4080 MCHBAR32(0x112c) = 0x63a01404;
4081 MCHBAR32(0x1130) = 0x609e1404;
4082 MCHBAR32(0x1134) = 0x5f9c1404;
4083 MCHBAR32(0x1138) = 0x5c961404;
4084 MCHBAR32(0x113c) = 0x58a02404;
4085 MCHBAR32(0x1140) = 0x54942404;
4086 MCHBAR32(0x1190) = 0x900080a;
4087 MCHBAR16(0x11c0) = 0xc40b;
4088 MCHBAR16(0x11c2) = 0x303;
4089 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004090 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004091 MCHBAR32(0x11b8) = 0x70c3000;
4092 MCHBAR8(0x11ec) = 0xa;
4093 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004094 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004095 MCHBAR16(0x11ca) = 0xfa;
4096 MCHBAR32(0x11e4) = 0x4e20;
4097 MCHBAR8(0x11bc) = 0xf;
4098 MCHBAR16(0x11da) = 0x19;
4099 MCHBAR16(0x11ba) = 0x470c;
4100 MCHBAR32(0x1680) = 0xe6ffe4ff;
4101 MCHBAR32(0x1684) = 0xdeffdaff;
4102 MCHBAR32(0x1688) = 0xd4ffd0ff;
4103 MCHBAR32(0x168c) = 0xccffc6ff;
4104 MCHBAR32(0x1690) = 0xc0ffbeff;
4105 MCHBAR32(0x1694) = 0xb8ffb0ff;
4106 MCHBAR32(0x1698) = 0xa8ff0000;
4107 MCHBAR32(0x169c) = 0xc00;
4108 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004109 }
4110
Felix Held04be2dd2018-07-29 04:53:22 +02004111 MCHBAR32(0x124c) = 0x15040d00;
4112 MCHBAR32(0x1250) = 0x7f0000;
4113 MCHBAR32(0x1254) = 0x1e220004;
4114 MCHBAR32(0x1258) = 0x4000004;
4115 MCHBAR32(0x1278) = 0x0;
4116 MCHBAR32(0x125c) = 0x0;
4117 MCHBAR32(0x1260) = 0x0;
4118 MCHBAR32(0x1264) = 0x0;
4119 MCHBAR32(0x1268) = 0x0;
4120 MCHBAR32(0x126c) = 0x0;
4121 MCHBAR32(0x1270) = 0x0;
4122 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004123 }
4124
4125 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004126 MCHBAR16(0x1214) = 0x320;
4127 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004128 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4129 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004130 MCHBAR32(0x1400) = 0x13040020;
4131 MCHBAR32(0x1404) = 0xe090120;
4132 MCHBAR32(0x1408) = 0x5120220;
4133 MCHBAR32(0x140c) = 0x5120330;
4134 MCHBAR32(0x1410) = 0xe090220;
4135 MCHBAR32(0x1414) = 0x1010001;
4136 MCHBAR32(0x1418) = 0x1110000;
4137 MCHBAR32(0x141c) = 0x9020020;
4138 MCHBAR32(0x1420) = 0xd090220;
4139 MCHBAR32(0x1424) = 0x2090220;
4140 MCHBAR32(0x1428) = 0x2090330;
4141 MCHBAR32(0x142c) = 0xd090220;
4142 MCHBAR32(0x1430) = 0x1010001;
4143 MCHBAR32(0x1434) = 0x1110000;
4144 MCHBAR32(0x1438) = 0x11040020;
4145 MCHBAR32(0x143c) = 0x4030220;
4146 MCHBAR32(0x1440) = 0x1060220;
4147 MCHBAR32(0x1444) = 0x1060330;
4148 MCHBAR32(0x1448) = 0x4030220;
4149 MCHBAR32(0x144c) = 0x1010001;
4150 MCHBAR32(0x1450) = 0x1110000;
4151 MCHBAR32(0x1454) = 0x4010020;
4152 MCHBAR32(0x1458) = 0xb090220;
4153 MCHBAR32(0x145c) = 0x1090220;
4154 MCHBAR32(0x1460) = 0x1090330;
4155 MCHBAR32(0x1464) = 0xb090220;
4156 MCHBAR32(0x1468) = 0x1010001;
4157 MCHBAR32(0x146c) = 0x1110000;
4158 MCHBAR32(0x1470) = 0xf040020;
4159 MCHBAR32(0x1474) = 0xa090220;
4160 MCHBAR32(0x1478) = 0x1120220;
4161 MCHBAR32(0x147c) = 0x1120330;
4162 MCHBAR32(0x1480) = 0xa090220;
4163 MCHBAR32(0x1484) = 0x1010001;
4164 MCHBAR32(0x1488) = 0x1110000;
4165 MCHBAR32(0x148c) = 0x7020020;
4166 MCHBAR32(0x1490) = 0x1010220;
4167 MCHBAR32(0x1494) = 0x10210;
4168 MCHBAR32(0x1498) = 0x10320;
4169 MCHBAR32(0x149c) = 0x1010220;
4170 MCHBAR32(0x14a0) = 0x1010001;
4171 MCHBAR32(0x14a4) = 0x1110000;
4172 MCHBAR32(0x14a8) = 0xd040020;
4173 MCHBAR32(0x14ac) = 0x8090220;
4174 MCHBAR32(0x14b0) = 0x1111310;
4175 MCHBAR32(0x14b4) = 0x1111420;
4176 MCHBAR32(0x14b8) = 0x8090220;
4177 MCHBAR32(0x14bc) = 0x1010001;
4178 MCHBAR32(0x14c0) = 0x1110000;
4179 MCHBAR32(0x14c4) = 0x3010020;
4180 MCHBAR32(0x14c8) = 0x7090220;
4181 MCHBAR32(0x14cc) = 0x1081310;
4182 MCHBAR32(0x14d0) = 0x1081420;
4183 MCHBAR32(0x14d4) = 0x7090220;
4184 MCHBAR32(0x14d8) = 0x1010001;
4185 MCHBAR32(0x14dc) = 0x1110000;
4186 MCHBAR32(0x14e0) = 0xb040020;
4187 MCHBAR32(0x14e4) = 0x2030220;
4188 MCHBAR32(0x14e8) = 0x1051310;
4189 MCHBAR32(0x14ec) = 0x1051420;
4190 MCHBAR32(0x14f0) = 0x2030220;
4191 MCHBAR32(0x14f4) = 0x1010001;
4192 MCHBAR32(0x14f8) = 0x1110000;
4193 MCHBAR32(0x14fc) = 0x5020020;
4194 MCHBAR32(0x1500) = 0x5090220;
4195 MCHBAR32(0x1504) = 0x2071310;
4196 MCHBAR32(0x1508) = 0x2071420;
4197 MCHBAR32(0x150c) = 0x5090220;
4198 MCHBAR32(0x1510) = 0x1010001;
4199 MCHBAR32(0x1514) = 0x1110000;
4200 MCHBAR32(0x1518) = 0x7040120;
4201 MCHBAR32(0x151c) = 0x2090220;
4202 MCHBAR32(0x1520) = 0x70b1210;
4203 MCHBAR32(0x1524) = 0x70b1310;
4204 MCHBAR32(0x1528) = 0x2090220;
4205 MCHBAR32(0x152c) = 0x1010001;
4206 MCHBAR32(0x1530) = 0x1110000;
4207 MCHBAR32(0x1534) = 0x1010110;
4208 MCHBAR32(0x1538) = 0x1081310;
4209 MCHBAR32(0x153c) = 0x5041200;
4210 MCHBAR32(0x1540) = 0x5041310;
4211 MCHBAR32(0x1544) = 0x1081310;
4212 MCHBAR32(0x1548) = 0x1010001;
4213 MCHBAR32(0x154c) = 0x1110000;
4214 MCHBAR32(0x1550) = 0x1040120;
4215 MCHBAR32(0x1554) = 0x4051210;
4216 MCHBAR32(0x1558) = 0xd051200;
4217 MCHBAR32(0x155c) = 0xd051200;
4218 MCHBAR32(0x1560) = 0x4051210;
4219 MCHBAR32(0x1564) = 0x1010001;
4220 MCHBAR32(0x1568) = 0x1110000;
4221 MCHBAR16(0x1222) = 0x220a;
4222 MCHBAR16(0x123c) = 0x1fc0;
4223 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004224 }
4225
Felix Heldf83d80b2018-07-29 05:30:30 +02004226 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004227 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004228 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004229
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004230 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004231
4232 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004233 MCHBAR8_AND(0x2ca8, ~3);
4234 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004235 /* This issues a CPU reset without resetting the platform */
4236 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004237 /* Write back the S3 state to PM1_CNT to let the reset CPU
4238 know it also needs to take the s3 path. */
4239 if (s3resume)
4240 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4241 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004242 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004243 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004244 }
4245
Felix Held04be2dd2018-07-29 04:53:22 +02004246 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004247 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004248 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004249 MCHBAR16(0x2c20); // !!!!
4250 MCHBAR16(0x2c10); // !!!!
4251 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004252 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253 udelay(1000);
4254 write_1d0(0, 0x33d, 0, 0);
4255 write_500(&info, 0, 0, 0xb61, 0, 0);
4256 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR32(0x1a30) = 0x0;
4258 MCHBAR32(0x1a34) = 0x0;
4259 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4260 (info.populated_ranks[0][0][0] * 0xa0);
4261 MCHBAR16(0x616) = 0x26a;
4262 MCHBAR32(0x134) = 0x856000;
4263 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004264 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4265 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004266 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004267 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4268 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004269 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004271 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4272 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004273 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4274 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4275 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4276 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4277 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4278 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4279 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4280 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4281 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4282 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004283 }
4284
4285 write_1d0(0x4, 0x151, 4, 1);
4286 write_1d0(0, 0x142, 3, 1);
4287 rdmsr(0x1ac); // !!!!
4288 write_500(&info, 1, 1, 0x6b3, 4, 1);
4289 write_500(&info, 1, 1, 0x6cf, 4, 1);
4290
4291 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4292
4293 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4294 populated_ranks[0]
4295 [0][0]) << 0),
4296 0x1d1, 3, 1);
4297 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004298 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4299 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004300 }
4301
4302 set_334(0);
4303
4304 program_base_timings(&info);
4305
Felix Held04be2dd2018-07-29 04:53:22 +02004306 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004307
4308 write_1d0(0x2, 0x1d5, 2, 1);
4309 write_1d0(0x20, 0x166, 7, 1);
4310 write_1d0(0x0, 0xeb, 3, 1);
4311 write_1d0(0x0, 0xf3, 6, 1);
4312
4313 for (channel = 0; channel < NUM_CHANNELS; channel++)
4314 for (lane = 0; lane < 9; lane++) {
4315 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4316 u8 a;
4317 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4318 write_500(&info, channel, a, addr, 6, 1);
4319 }
4320
4321 udelay(1000);
4322
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323 if (s3resume) {
4324 if (info.cached_training == NULL) {
4325 u32 reg32;
4326 printk(BIOS_ERR,
4327 "Couldn't find training data. Rebooting\n");
4328 reg32 = inl(DEFAULT_PMBASE + 0x04);
4329 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004330 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004331 }
4332 int tm;
4333 info.training = *info.cached_training;
4334 for (tm = 0; tm < 4; tm++)
4335 for (channel = 0; channel < NUM_CHANNELS; channel++)
4336 for (slot = 0; slot < NUM_SLOTS; slot++)
4337 for (rank = 0; rank < NUM_RANKS; rank++)
4338 for (lane = 0; lane < 9; lane++)
4339 write_500(&info,
4340 channel,
4341 info.training.
4342 lane_timings
4343 [tm][channel]
4344 [slot][rank]
4345 [lane],
4346 get_timing_register_addr
4347 (lane, tm,
4348 slot, rank),
4349 9, 0);
4350 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4351 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4352 }
4353
Felix Heldf83d80b2018-07-29 05:30:30 +02004354 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004355 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004356 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004357 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004358
4359 program_board_delay(&info);
4360
Felix Held04be2dd2018-07-29 04:53:22 +02004361 MCHBAR8(0x5ff) = 0x0;
4362 MCHBAR8(0x5ff) = 0x80;
4363 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004364
Felix Held04be2dd2018-07-29 04:53:22 +02004365 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004366 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004367 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004368 gav(read_1d0(0x14b, 7)); // = 0x81023100
4369 write_1d0(0x30, 0x14b, 7, 1);
4370 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4371 write_1d0(7, 0xd6, 6, 1);
4372 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4373 write_1d0(7, 0x328, 6, 1);
4374
4375 for (channel = 0; channel < NUM_CHANNELS; channel++)
4376 set_4cf(&info, channel,
4377 info.populated_ranks[channel][0][0] ? 8 : 0);
4378
4379 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4380 write_1d0(2, 0x116, 4, 1);
4381 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4382 write_1d0(0, 0xae, 6, 1);
4383 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4384 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004385 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4386 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004387 MCHBAR32_AND(0x140, ~0x07000000);
4388 MCHBAR32_AND(0x138, ~0x07000000);
4389 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004390 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004391 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004392 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004393
4394 {
4395 u32 t;
4396 u8 val_a1;
4397 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4398 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4399 rmw_1d0(0x320, 0x07,
4400 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4401 rmw_1d0(0x14b, 0x78,
4402 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4403 4), 7,
4404 1);
4405 rmw_1d0(0xce, 0x38,
4406 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4407 4), 6,
4408 1);
4409 }
4410
4411 for (channel = 0; channel < NUM_CHANNELS; channel++)
4412 set_4cf(&info, channel,
4413 info.populated_ranks[channel][0][0] ? 9 : 1);
4414
4415 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004416 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004417 write_1d0(2, 0xae, 6, 1);
4418 write_1d0(2, 0x300, 6, 1);
4419 write_1d0(2, 0x121, 3, 1);
4420 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4421 write_1d0(4, 0xd6, 6, 1);
4422 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4423 write_1d0(4, 0x328, 6, 1);
4424
4425 for (channel = 0; channel < NUM_CHANNELS; channel++)
4426 set_4cf(&info, channel,
4427 info.populated_ranks[channel][0][0] ? 9 : 0);
4428
Felix Held04be2dd2018-07-29 04:53:22 +02004429 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4430 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004431 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004432 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004433 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4434 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4435 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4436 write_1d0(0, 0x21c, 6, 1);
4437 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4438 write_1d0(0x35, 0x14b, 7, 1);
4439
4440 for (channel = 0; channel < NUM_CHANNELS; channel++)
4441 set_4cf(&info, channel,
4442 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4443
4444 set_334(1);
4445
Felix Held04be2dd2018-07-29 04:53:22 +02004446 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004447
4448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4449 write_500(&info, channel,
4450 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4451 1);
4452 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4453 }
Felix Held04be2dd2018-07-29 04:53:22 +02004454 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4455 MCHBAR16(0x6c0) = 0x14a0;
4456 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4457 MCHBAR16(0x232) = 0x8;
4458 /* 0x40004 or 0 depending on ? */
4459 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4460 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4461 MCHBAR32(0x128) = 0x2150d05;
4462 MCHBAR8(0x12c) = 0x1f;
4463 MCHBAR8(0x12d) = 0x56;
4464 MCHBAR8(0x12e) = 0x31;
4465 MCHBAR8(0x12f) = 0x0;
4466 MCHBAR8(0x271) = 0x2;
4467 MCHBAR8(0x671) = 0x2;
4468 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004469 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004470 MCHBAR32(0x294 + (channel << 10)) =
4471 (info.populated_ranks_mask[channel] & 3) << 16;
4472 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4473 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004474 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004475 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4476 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004477
4478 if (!s3resume)
4479 jedec_init(&info);
4480
4481 int totalrank = 0;
4482 for (channel = 0; channel < NUM_CHANNELS; channel++)
4483 for (slot = 0; slot < NUM_SLOTS; slot++)
4484 for (rank = 0; rank < NUM_RANKS; rank++)
4485 if (info.populated_ranks[channel][slot][rank]) {
4486 jedec_read(&info, channel, slot, rank,
4487 totalrank, 0xa, 0x400);
4488 totalrank++;
4489 }
4490
Felix Held04be2dd2018-07-29 04:53:22 +02004491 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492
Felix Heldf83d80b2018-07-29 05:30:30 +02004493 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4494 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495
4496 if (!s3resume) {
4497 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR32(0x294 + (channel << 10)) =
4499 (info.populated_ranks_mask[channel] & 3) << 16;
4500 MCHBAR16(0x298 + (channel << 10)) =
4501 info.populated_ranks[channel][0][0] |
4502 (info.populated_ranks[channel][0][1] << 5);
4503 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004505 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506
4507 {
4508 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004509 a = MCHBAR8(0x243);
4510 b = MCHBAR8(0x643);
4511 MCHBAR8(0x243) = a | 2;
4512 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 }
4514
4515 write_1d0(7, 0x19b, 3, 1);
4516 write_1d0(7, 0x1c0, 3, 1);
4517 write_1d0(4, 0x1c6, 4, 1);
4518 write_1d0(4, 0x1cc, 4, 1);
4519 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4520 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004521 MCHBAR32(0x584) = 0xfffff;
4522 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523
4524 for (channel = 0; channel < NUM_CHANNELS; channel++)
4525 for (slot = 0; slot < NUM_SLOTS; slot++)
4526 for (rank = 0; rank < NUM_RANKS; rank++)
4527 if (info.
4528 populated_ranks[channel][slot]
4529 [rank])
4530 config_rank(&info, s3resume,
4531 channel, slot,
4532 rank);
4533
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR8(0x243) = 0x1;
4535 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004536 }
4537
4538 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004539 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540 write_26c(0, 0x820);
4541 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004542 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 /* end */
4544
4545 if (s3resume) {
4546 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR32(0x294 + (channel << 10)) =
4548 (info.populated_ranks_mask[channel] & 3) << 16;
4549 MCHBAR16(0x298 + (channel << 10)) =
4550 info.populated_ranks[channel][0][0] |
4551 (info.populated_ranks[channel][0][1] << 5);
4552 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004554 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004555 }
4556
Felix Held04be2dd2018-07-29 04:53:22 +02004557 MCHBAR32_AND(0xfa4, ~0x01000002);
4558 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 /* Before training. */
4561 timestamp_add_now(103);
4562
4563 if (!s3resume)
4564 ram_training(&info);
4565
4566 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004567 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568
4569 dump_timings(&info);
4570
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 program_modules_memory_map(&info, 0);
4572 program_total_memory_map(&info);
4573
4574 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580 else
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR32_AND(0xfac, ~0x80000000);
4584 MCHBAR32(0xfb4) = 0x4800;
4585 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4586 MCHBAR32(0xe94) = 0x7ffff;
4587 MCHBAR32(0xfc0) = 0x80002040;
4588 MCHBAR32(0xfc4) = 0x701246;
4589 MCHBAR8_AND(0xfc8, ~0x70);
4590 MCHBAR32_OR(0xe5c, 0x1000000);
4591 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4592 MCHBAR32(0x50) = 0x700b0;
4593 MCHBAR32(0x3c) = 0x10;
4594 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4595 MCHBAR8_OR(0xff4, 0x2);
4596 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597
Felix Held29a9c072018-07-29 01:34:45 +02004598#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4600 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4601 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004602
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004603 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4604 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4605 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004606
4607#else
4608 {
4609 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004610 // = 0xe911714b
4611 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4612 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4613 // = 0xe911714b
4614 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4615 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004616 }
4617#endif
4618
4619 {
4620 u32 eax;
4621
4622 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004623 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4624 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4625 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626 }
4627
4628 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004631 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632 else
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636
Felix Held04be2dd2018-07-29 04:53:22 +02004637 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004639 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004640 else
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642 }
4643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645
4646 {
4647 u8 al;
4648 al = 0xd;
4649 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4650 al += 2;
4651 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653 }
4654
4655 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4657 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4658 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4659 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004662 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004663 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004664 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004665 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004666 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004667 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004668 MCHBAR8_OR(0x1210, 2);
4669 MCHBAR32(0x1200) = 0x8800440;
4670 MCHBAR32(0x1204) = 0x53ff0453;
4671 MCHBAR32(0x1208) = 0x19002043;
4672 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
4674 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR16(0x1214) = 0x220;
4676 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677 }
4678
Felix Held04be2dd2018-07-29 04:53:22 +02004679 MCHBAR8_OR(0x1214, 0x4);
4680 MCHBAR8(0x120c) = 0x1;
4681 MCHBAR8(0x1218) = 0x3;
4682 MCHBAR8(0x121a) = 0x3;
4683 MCHBAR8(0x121c) = 0x3;
4684 MCHBAR16(0xc14) = 0x0;
4685 MCHBAR16(0xc20) = 0x0;
4686 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004687
4688 /* revision dependent here. */
4689
Felix Held04be2dd2018-07-29 04:53:22 +02004690 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
4692 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
Felix Held04be2dd2018-07-29 04:53:22 +02004695 MCHBAR16_OR(0x1230, 0x8000);
4696 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697
4698 u8 bl, ebpb;
4699 u16 reg_1020;
4700
Felix Held04be2dd2018-07-29 04:53:22 +02004701 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4702 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
Felix Held04be2dd2018-07-29 04:53:22 +02004704 MCHBAR32(0x1000) = 0x100;
4705 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004706
4707 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 bl = reg_1020 >> 8;
4710 ebpb = reg_1020 & 0xff;
4711 } else {
4712 ebpb = 0;
4713 bl = 8;
4714 }
4715
4716 rdmsr(0x1a2);
4717
Felix Held04be2dd2018-07-29 04:53:22 +02004718 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719
Felix Held04be2dd2018-07-29 04:53:22 +02004720 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004723
Felix Held04be2dd2018-07-29 04:53:22 +02004724 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004726 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4727 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004728 }
4729
4730 setup_heci_uma(&info);
4731
4732 if (info.uma_enabled) {
4733 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004734 MCHBAR32_OR(0x11b0, 0x4000);
4735 MCHBAR32_OR(0x11b4, 0x4000);
4736 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004737
Felix Held04be2dd2018-07-29 04:53:22 +02004738 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4739 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4740 MCHBAR16_OR(0x1170, 0x1000);
4741
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004742 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004743
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004745 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004746 ;
4747 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004748 }
4749
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004750 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4751 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004752 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004753 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755 udelay(1000);
4756 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004757 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4758
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004759 if (!s3resume)
4760 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004761 if (s3resume && cbmem_wasnot_inited) {
4762 u32 reg32;
4763 printk(BIOS_ERR, "Failed S3 resume.\n");
4764 ram_check(0x100000, 0x200000);
4765
4766 /* Clear SLP_TYPE. */
4767 reg32 = inl(DEFAULT_PMBASE + 0x04);
4768 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4769
4770 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004771 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004772 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004773}