blob: e8e2c08abd8d70fda1d08e4fde5db816b59d6cda [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
58/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
59typedef struct {
60 u8 smallest;
61 u8 largest;
62} timing_bounds_t[2][2][2][9];
63
Angel Pons36592bf2020-09-14 18:52:44 +020064#define MRC_CACHE_VERSION 3
Arthur Heymansdc71e252018-01-29 10:14:48 +010065
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010066struct ram_training {
67 /* [TM][CHANNEL][SLOT][RANK][LANE] */
68 u16 lane_timings[4][2][2][2][9];
69 u16 reg_178;
70 u16 reg_10b;
71
72 u8 reg178_center;
73 u8 reg178_smallest;
74 u8 reg178_largest;
75 timing_bounds_t timing_bounds[2];
76 u16 timing_offset[2][2][2][9];
77 u16 timing2_offset[2][2][2][9];
78 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010079 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
80 u8 reg2ca9_bit0;
81 u32 reg_6dc;
82 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010083};
84
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010085#include <lib.h> /* Prototypes */
86
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010087typedef struct _u128 {
88 u64 lo;
89 u64 hi;
90} u128;
91
92static void read128(u32 addr, u64 * out)
93{
94 u128 ret;
95 u128 stor;
96 asm volatile ("movdqu %%xmm0, %0\n"
97 "movdqa (%2), %%xmm0\n"
98 "movdqu %%xmm0, %1\n"
99 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
100 out[0] = ret.lo;
101 out[1] = ret.hi;
102}
103
Angel Ponsc2d6f5f2020-12-11 23:48:51 +0100104/*
105 * Ironlake memory I/O timings are located in scan chains, accessible
106 * through MCHBAR register groups. Each channel has a scan chain, and
107 * there's a global scan chain too. Each chain is broken into smaller
108 * sections of N bits, where N <= 32. Each section allows reading and
109 * writing a certain parameter. Each section contains N - 2 data bits
110 * and two additional bits: a Mask bit, and a Halt bit.
111 */
112
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100113/* OK */
114static void write_1d0(u32 val, u16 addr, int bits, int flag)
115{
Felix Held04be2dd2018-07-29 04:53:22 +0200116 MCHBAR32(0x1d0) = 0;
117 while (MCHBAR32(0x1d0) & 0x800000)
118 ;
119 MCHBAR32(0x1d4) =
120 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
121 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200122 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200123 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100124}
125
126/* OK */
127static u16 read_1d0(u16 addr, int split)
128{
129 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200130 MCHBAR32(0x1d0) = 0;
131 while (MCHBAR32(0x1d0) & 0x800000)
132 ;
133 MCHBAR32(0x1d0) =
134 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
135 while (MCHBAR32(0x1d0) & 0x800000)
136 ;
137 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100138 write_1d0(0, 0x33d, 0, 0);
139 write_1d0(0, 0x33d, 0, 0);
140 val &= ((1 << split) - 1);
141 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
142 return val;
143}
144
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800145static void write32p(uintptr_t addr, uint32_t val)
146{
147 write32((void *)addr, val);
148}
149
150static uint32_t read32p(uintptr_t addr)
151{
152 return read32((void *)addr);
153}
154
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100155static void sfence(void)
156{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100157 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100158}
159
160static inline u16 get_lane_offset(int slot, int rank, int lane)
161{
162 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
163 0x452 * (lane == 8);
164}
165
166static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
167{
168 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
169 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
170}
171
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100172static u32 gav_real(int line, u32 in)
173{
174 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
175 return in;
176}
177
178#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180struct raminfo {
181 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
182 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
183 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
184 u8 density[2][2]; /* [CHANNEL][SLOT] */
185 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
186 int rank_start[2][2][2];
187 u8 cas_latency;
188 u8 board_lane_delay[9];
189 u8 use_ecc;
190 u8 revision;
191 u8 max_supported_clock_speed_index;
192 u8 uma_enabled;
193 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
194 u8 silicon_revision;
195 u8 populated_ranks_mask[2];
196 u8 max_slots_used_in_channel;
197 u8 mode4030[2];
198 u16 avg4044[2];
199 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600200 unsigned int total_memory_mb;
201 unsigned int interleaved_part_mb;
202 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100203
Martin Roth468d02c2019-10-23 21:44:42 -0600204 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100205
206 struct ram_training training;
207 u32 last_500_command[2];
208
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209 u32 delay46_ps[2];
210 u32 delay54_ps[2];
211 u8 revision_flag_1;
212 u8 some_delay_1_cycle_floor;
213 u8 some_delay_2_halfcycles_ceil;
214 u8 some_delay_3_ps_rounded;
215
216 const struct ram_training *cached_training;
217};
218
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200219/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100220timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200221
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100222static void
223write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
224 int flag);
225
226/* OK */
227static u16
228read_500(struct raminfo *info, int channel, u16 addr, int split)
229{
230 u32 val;
231 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200232 MCHBAR32(0x500 + (channel << 10)) = 0;
233 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
234 ;
235 MCHBAR32(0x500 + (channel << 10)) =
236 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
237 + 0xb88 - addr);
238 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
239 ;
240 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100241 return val & ((1 << split) - 1);
242}
243
244/* OK */
245static void
246write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
247 int flag)
248{
249 if (info->last_500_command[channel] == 0x80000000) {
250 info->last_500_command[channel] = 0x40000000;
251 write_500(info, channel, 0, 0xb61, 0, 0);
252 }
Felix Held04be2dd2018-07-29 04:53:22 +0200253 MCHBAR32(0x500 + (channel << 10)) = 0;
254 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
255 ;
256 MCHBAR32(0x504 + (channel << 10)) =
257 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
258 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200259 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200260 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261}
262
Angel Ponsc10f8b22021-01-15 20:34:51 +0100263static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
264{
265 const u32 val = read_500(info, channel, addr, bits) & and;
266 write_500(info, channel, val | or, addr, bits, 1);
267}
268
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100269static int rw_test(int rank)
270{
271 const u32 mask = 0xf00fc33c;
272 int ok = 0xff;
273 int i;
274 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800275 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276 sfence();
277 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800278 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100279 sfence();
280 for (i = 0; i < 32; i++) {
281 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 write32p((rank << 28) | (i << 3), pat);
283 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100284 }
285 sfence();
286 for (i = 0; i < 32; i++) {
287 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
288 int j;
289 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800290 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291 for (j = 0; j < 4; j++)
292 if (((val >> (j * 8)) & 0xff) != pat)
293 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(16 << j);
298 }
299 sfence();
300 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800301 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100302 sfence();
303 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800304 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100305
306 return ok;
307}
308
309static void
310program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
311{
312 int lane;
313 for (lane = 0; lane < 8; lane++) {
314 write_500(info, channel,
315 base +
316 info->training.
317 lane_timings[2][channel][slot][rank][lane],
318 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
319 write_500(info, channel,
320 base +
321 info->training.
322 lane_timings[3][channel][slot][rank][lane],
323 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
324 }
325}
326
327static void write_26c(int channel, u16 si)
328{
Felix Held04be2dd2018-07-29 04:53:22 +0200329 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
330 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
331 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332}
333
Angel Ponsc627dc92020-09-22 17:06:44 +0200334static void toggle_1d0_142_5ff(void)
335{
336 u32 reg32 = gav(read_1d0(0x142, 3));
337 if (reg32 & (1 << 1))
338 write_1d0(0, 0x142, 3, 1);
339
340 MCHBAR8(0x5ff) = 0x0;
341 MCHBAR8(0x5ff) = 0x80;
342 if (reg32 & (1 << 1))
343 write_1d0(0x2, 0x142, 3, 1);
344}
345
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100346static u32 get_580(int channel, u8 addr)
347{
348 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200349 toggle_1d0_142_5ff();
Felix Held04be2dd2018-07-29 04:53:22 +0200350 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
351 MCHBAR8_OR(0x580 + (channel << 10), 1);
352 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
353 ;
354 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100355 return ret;
356}
357
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100358#define NUM_CHANNELS 2
359#define NUM_SLOTS 2
360#define NUM_RANKS 2
361#define RANK_SHIFT 28
362#define CHANNEL_SHIFT 10
363
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100364static void seq9(struct raminfo *info, int channel, int slot, int rank)
365{
366 int i, lane;
367
368 for (i = 0; i < 2; i++)
369 for (lane = 0; lane < 8; lane++)
370 write_500(info, channel,
371 info->training.lane_timings[i +
372 1][channel][slot]
373 [rank][lane], get_timing_register_addr(lane,
374 i + 1,
375 slot,
376 rank),
377 9, 0);
378
379 write_1d0(1, 0x103, 6, 1);
380 for (lane = 0; lane < 8; lane++)
381 write_500(info, channel,
382 info->training.
383 lane_timings[0][channel][slot][rank][lane],
384 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
385
386 for (i = 0; i < 2; i++) {
387 for (lane = 0; lane < 8; lane++)
388 write_500(info, channel,
389 info->training.lane_timings[i +
390 1][channel][slot]
391 [rank][lane], get_timing_register_addr(lane,
392 i + 1,
393 slot,
394 rank),
395 9, 0);
396 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
397 }
398
Angel Ponsc627dc92020-09-22 17:06:44 +0200399 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100400 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200401
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100402 for (lane = 0; lane < 8; lane++) {
403 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
404 info->training.lane_timings[2][channel][slot][rank][lane] =
405 read_500(info, channel,
406 get_timing_register_addr(lane, 2, slot, rank), 9);
407 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
408 info->training.lane_timings[3][channel][slot][rank][lane] =
409 info->training.lane_timings[2][channel][slot][rank][lane] +
410 0x20;
411 }
412}
413
414static int count_ranks_in_channel(struct raminfo *info, int channel)
415{
416 int slot, rank;
417 int res = 0;
418 for (slot = 0; slot < NUM_SLOTS; slot++)
419 for (rank = 0; rank < NUM_SLOTS; rank++)
420 res += info->populated_ranks[channel][slot][rank];
421 return res;
422}
423
424static void
425config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
426{
427 int add;
428
429 write_1d0(0, 0x178, 7, 1);
430 seq9(info, channel, slot, rank);
431 program_timings(info, 0x80, channel, slot, rank);
432
433 if (channel == 0)
434 add = count_ranks_in_channel(info, 1);
435 else
436 add = 0;
437 if (!s3resume)
438 gav(rw_test(rank + add));
439 program_timings(info, 0x00, channel, slot, rank);
440 if (!s3resume)
441 gav(rw_test(rank + add));
442 if (!s3resume)
443 gav(rw_test(rank + add));
444 write_1d0(0, 0x142, 3, 1);
445 write_1d0(0, 0x103, 6, 1);
446
447 gav(get_580(channel, 0xc | (rank << 5)));
448 gav(read_1d0(0x142, 3));
449
Felix Held04be2dd2018-07-29 04:53:22 +0200450 MCHBAR8(0x5ff) = 0x0;
451 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100452}
453
Angel Ponsc10f8b22021-01-15 20:34:51 +0100454static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100455{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100456 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
457
458 val &= 1;
459 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
460 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100461}
462
463static void set_334(int zero)
464{
465 int j, k, channel;
466 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
467 u32 vd8[2][16];
468
469 for (channel = 0; channel < NUM_CHANNELS; channel++) {
470 for (j = 0; j < 4; j++) {
471 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
472 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
473 u16 c;
474 if ((j == 0 || j == 3) && zero)
475 c = 0;
476 else if (j == 3)
477 c = 0x5f;
478 else
479 c = 0x5f5f;
480
481 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32(0x138 + 8 * k) =
483 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200487 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100488 }
489
Felix Held22ca8cb2018-07-29 05:09:44 +0200490 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200492 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
493 zero ? 0 : (0x18191819 & lmask);
494 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
495 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
496 zero ? 0 : (a & lmask);
497 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
498 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499 }
500 }
501
Felix Held04be2dd2018-07-29 04:53:22 +0200502 MCHBAR32_OR(0x130, 1);
503 while (MCHBAR8(0x130) & 1)
504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100505}
506
Angel Pons244f4552021-01-15 20:41:36 +0100507static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100508{
509 u32 v;
510 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100511 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100512}
513
514static int find_highest_bit_set(u16 val)
515{
516 int i;
517 for (i = 15; i >= 0; i--)
518 if (val & (1 << i))
519 return i;
520 return -1;
521}
522
523static int find_lowest_bit_set32(u32 val)
524{
525 int i;
526 for (i = 0; i < 32; i++)
527 if (val & (1 << i))
528 return i;
529 return -1;
530}
531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100532enum {
533 DEVICE_TYPE = 2,
534 MODULE_TYPE = 3,
535 DENSITY = 4,
536 RANKS_AND_DQ = 7,
537 MEMORY_BUS_WIDTH = 8,
538 TIMEBASE_DIVIDEND = 10,
539 TIMEBASE_DIVISOR = 11,
540 CYCLETIME = 12,
541
542 CAS_LATENCIES_LSB = 14,
543 CAS_LATENCIES_MSB = 15,
544 CAS_LATENCY_TIME = 16,
545 THERMAL_AND_REFRESH = 31,
546 REFERENCE_RAW_CARD_USED = 62,
547 RANK1_ADDRESS_MAPPING = 63
548};
549
550static void calculate_timings(struct raminfo *info)
551{
Martin Roth468d02c2019-10-23 21:44:42 -0600552 unsigned int cycletime;
553 unsigned int cas_latency_time;
554 unsigned int supported_cas_latencies;
555 unsigned int channel, slot;
556 unsigned int clock_speed_index;
557 unsigned int min_cas_latency;
558 unsigned int cas_latency;
559 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100560
561 /* Find common CAS latency */
562 supported_cas_latencies = 0x3fe;
563 for (channel = 0; channel < NUM_CHANNELS; channel++)
564 for (slot = 0; slot < NUM_SLOTS; slot++)
565 if (info->populated_ranks[channel][slot][0])
566 supported_cas_latencies &=
567 2 *
568 (info->
569 spd[channel][slot][CAS_LATENCIES_LSB] |
570 (info->
571 spd[channel][slot][CAS_LATENCIES_MSB] <<
572 8));
573
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100574 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100575
576 cycletime = min_cycletime[max_clock_index];
577 cas_latency_time = min_cas_latency_time[max_clock_index];
578
579 for (channel = 0; channel < NUM_CHANNELS; channel++)
580 for (slot = 0; slot < NUM_SLOTS; slot++)
581 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600582 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100589 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100593 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
Jacob Garber3c193822019-06-10 18:23:32 -0600598 if (cycletime > min_cycletime[0])
599 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100600 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
601 if (cycletime == min_cycletime[clock_speed_index])
602 break;
603 if (cycletime > min_cycletime[clock_speed_index]) {
604 clock_speed_index--;
605 cycletime = min_cycletime[clock_speed_index];
606 break;
607 }
608 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100609 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100610 cas_latency = 0;
611 while (supported_cas_latencies) {
612 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
613 if (cas_latency <= min_cas_latency)
614 break;
615 supported_cas_latencies &=
616 ~(1 << find_highest_bit_set(supported_cas_latencies));
617 }
618
619 if (cas_latency != min_cas_latency && clock_speed_index)
620 clock_speed_index--;
621
622 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
623 die("Couldn't configure DRAM");
624 info->clock_speed_index = clock_speed_index;
625 info->cas_latency = cas_latency;
626}
627
628static void program_base_timings(struct raminfo *info)
629{
Martin Roth468d02c2019-10-23 21:44:42 -0600630 unsigned int channel;
631 unsigned int slot, rank, lane;
632 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100633 int i;
634
635 extended_silicon_revision = info->silicon_revision;
636 if (info->silicon_revision == 0)
637 for (channel = 0; channel < NUM_CHANNELS; channel++)
638 for (slot = 0; slot < NUM_SLOTS; slot++)
639 if ((info->
640 spd[channel][slot][MODULE_TYPE] & 0xF) ==
641 3)
642 extended_silicon_revision = 4;
643
644 for (channel = 0; channel < NUM_CHANNELS; channel++) {
645 for (slot = 0; slot < NUM_SLOTS; slot++)
646 for (rank = 0; rank < NUM_SLOTS; rank++) {
647 int card_timing_2;
648 if (!info->populated_ranks[channel][slot][rank])
649 continue;
650
651 for (lane = 0; lane < 9; lane++) {
652 int tm_reg;
653 int card_timing;
654
655 card_timing = 0;
656 if ((info->
657 spd[channel][slot][MODULE_TYPE] &
658 0xF) == 3) {
659 int reference_card;
660 reference_card =
661 info->
662 spd[channel][slot]
663 [REFERENCE_RAW_CARD_USED] &
664 0x1f;
665 if (reference_card == 3)
666 card_timing =
667 u16_ffd1188[0][lane]
668 [info->
669 clock_speed_index];
670 if (reference_card == 5)
671 card_timing =
672 u16_ffd1188[1][lane]
673 [info->
674 clock_speed_index];
675 }
676
677 info->training.
678 lane_timings[0][channel][slot][rank]
679 [lane] =
680 u8_FFFD1218[info->
681 clock_speed_index];
682 info->training.
683 lane_timings[1][channel][slot][rank]
684 [lane] = 256;
685
686 for (tm_reg = 2; tm_reg < 4; tm_reg++)
687 info->training.
688 lane_timings[tm_reg]
689 [channel][slot][rank][lane]
690 =
691 u8_FFFD1240[channel]
692 [extended_silicon_revision]
693 [lane][2 * slot +
694 rank][info->
695 clock_speed_index]
696 + info->max4048[channel]
697 +
698 u8_FFFD0C78[channel]
699 [extended_silicon_revision]
700 [info->
701 mode4030[channel]][slot]
702 [rank][info->
703 clock_speed_index]
704 + card_timing;
705 for (tm_reg = 0; tm_reg < 4; tm_reg++)
706 write_500(info, channel,
707 info->training.
708 lane_timings[tm_reg]
709 [channel][slot][rank]
710 [lane],
711 get_timing_register_addr
712 (lane, tm_reg, slot,
713 rank), 9, 0);
714 }
715
716 card_timing_2 = 0;
717 if (!(extended_silicon_revision != 4
718 || (info->
719 populated_ranks_mask[channel] & 5) ==
720 5)) {
721 if ((info->
722 spd[channel][slot]
723 [REFERENCE_RAW_CARD_USED] & 0x1F)
724 == 3)
725 card_timing_2 =
726 u16_FFFE0EB8[0][info->
727 clock_speed_index];
728 if ((info->
729 spd[channel][slot]
730 [REFERENCE_RAW_CARD_USED] & 0x1F)
731 == 5)
732 card_timing_2 =
733 u16_FFFE0EB8[1][info->
734 clock_speed_index];
735 }
736
737 for (i = 0; i < 3; i++)
738 write_500(info, channel,
739 (card_timing_2 +
740 info->max4048[channel]
741 +
742 u8_FFFD0EF8[channel]
743 [extended_silicon_revision]
744 [info->
745 mode4030[channel]][info->
746 clock_speed_index]),
747 u16_fffd0c50[i][slot][rank],
748 8, 1);
749 write_500(info, channel,
750 (info->max4048[channel] +
751 u8_FFFD0C78[channel]
752 [extended_silicon_revision][info->
753 mode4030
754 [channel]]
755 [slot][rank][info->
756 clock_speed_index]),
757 u16_fffd0c70[slot][rank], 7, 1);
758 }
759 if (!info->populated_ranks_mask[channel])
760 continue;
761 for (i = 0; i < 3; i++)
762 write_500(info, channel,
763 (info->max4048[channel] +
764 info->avg4044[channel]
765 +
766 u8_FFFD17E0[channel]
767 [extended_silicon_revision][info->
768 mode4030
769 [channel]][info->
770 clock_speed_index]),
771 u16_fffd0c68[i], 8, 1);
772 }
773}
774
775static unsigned int fsbcycle_ps(struct raminfo *info)
776{
777 return 900000 / info->fsb_frequency;
778}
779
780/* The time of DDR transfer in ps. */
781static unsigned int halfcycle_ps(struct raminfo *info)
782{
783 return 3750 / (info->clock_speed_index + 3);
784}
785
786/* The time of clock cycle in ps. */
787static unsigned int cycle_ps(struct raminfo *info)
788{
789 return 2 * halfcycle_ps(info);
790}
791
792/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600793static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100794{
795 return (info->clock_speed_index + 3) * 120;
796}
797
798/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600799static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100800{
801 return 100 * frequency_11(info) / 9;
802}
803
Martin Roth468d02c2019-10-23 21:44:42 -0600804static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100805{
806 return (frequency_11(info) * 2) * ps / 900000;
807}
808
Martin Roth468d02c2019-10-23 21:44:42 -0600809static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100810{
811 return (frequency_11(info)) * ns / 900;
812}
813
814static void compute_derived_timings(struct raminfo *info)
815{
Martin Roth468d02c2019-10-23 21:44:42 -0600816 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100817 int extended_silicon_revision;
818 int some_delay_1_ps;
819 int some_delay_2_ps;
820 int some_delay_2_halfcycles_ceil;
821 int some_delay_2_halfcycles_floor;
822 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100823 int some_delay_3_ps_rounded;
824 int some_delay_1_cycle_ceil;
825 int some_delay_1_cycle_floor;
826
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100827 some_delay_3_ps_rounded = 0;
828 extended_silicon_revision = info->silicon_revision;
829 if (!info->silicon_revision)
830 for (channel = 0; channel < NUM_CHANNELS; channel++)
831 for (slot = 0; slot < NUM_SLOTS; slot++)
832 if ((info->
833 spd[channel][slot][MODULE_TYPE] & 0xF) ==
834 3)
835 extended_silicon_revision = 4;
836 if (info->board_lane_delay[7] < 5)
837 info->board_lane_delay[7] = 5;
838 info->revision_flag_1 = 2;
839 if (info->silicon_revision == 2 || info->silicon_revision == 3)
840 info->revision_flag_1 = 0;
841 if (info->revision < 16)
842 info->revision_flag_1 = 0;
843
844 if (info->revision < 8)
845 info->revision_flag_1 = 0;
846 if (info->revision >= 8 && (info->silicon_revision == 0
847 || info->silicon_revision == 1))
848 some_delay_2_ps = 735;
849 else
850 some_delay_2_ps = 750;
851
852 if (info->revision >= 0x10 && (info->silicon_revision == 0
853 || info->silicon_revision == 1))
854 some_delay_1_ps = 3929;
855 else
856 some_delay_1_ps = 3490;
857
858 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
859 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
860 if (some_delay_1_ps % cycle_ps(info))
861 some_delay_1_cycle_ceil++;
862 else
863 some_delay_1_cycle_floor--;
864 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
865 if (info->revision_flag_1)
866 some_delay_2_ps = halfcycle_ps(info) >> 6;
867 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100868 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100869 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
870 375;
871 some_delay_3_ps =
872 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
873 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200874 if (some_delay_3_ps >= 150) {
875 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100876 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200877 some_delay_3_ps_rounded =
878 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
879 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100880 }
881 some_delay_2_halfcycles_ceil =
882 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
883 2 * (some_delay_1_cycle_ceil - 1);
884 if (info->revision_flag_1 && some_delay_3_ps < 150)
885 some_delay_2_halfcycles_ceil++;
886 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
887 if (info->revision < 0x10)
888 some_delay_2_halfcycles_floor =
889 some_delay_2_halfcycles_ceil - 1;
890 if (!info->revision_flag_1)
891 some_delay_2_halfcycles_floor++;
892 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
893 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
894 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
895 || (info->populated_ranks[1][0][0]
896 && info->populated_ranks[1][1][0]))
897 info->max_slots_used_in_channel = 2;
898 else
899 info->max_slots_used_in_channel = 1;
900 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200901 MCHBAR32(0x244 + (channel << 10)) =
902 ((info->revision < 8) ? 1 : 0x200) |
903 ((2 - info->max_slots_used_in_channel) << 17) |
904 (channel << 21) |
905 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100906 if (info->max_slots_used_in_channel == 1) {
907 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
908 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
909 } else {
910 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 */
911 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
912 || (count_ranks_in_channel(info, 1) ==
913 2)) ? 2 : 3;
914 }
915 for (channel = 0; channel < NUM_CHANNELS; channel++) {
916 int max_of_unk;
917 int min_of_unk_2;
918
919 int i, count;
920 int sum;
921
922 if (!info->populated_ranks_mask[channel])
923 continue;
924
925 max_of_unk = 0;
926 min_of_unk_2 = 32767;
927
928 sum = 0;
929 count = 0;
930 for (i = 0; i < 3; i++) {
931 int unk1;
932 if (info->revision < 8)
933 unk1 =
934 u8_FFFD1891[0][channel][info->
935 clock_speed_index]
936 [i];
937 else if (!
938 (info->revision >= 0x10
939 || info->revision_flag_1))
940 unk1 =
941 u8_FFFD1891[1][channel][info->
942 clock_speed_index]
943 [i];
944 else
945 unk1 = 0;
946 for (slot = 0; slot < NUM_SLOTS; slot++)
947 for (rank = 0; rank < NUM_RANKS; rank++) {
948 int a = 0;
949 int b = 0;
950
951 if (!info->
952 populated_ranks[channel][slot]
953 [rank])
954 continue;
955 if (extended_silicon_revision == 4
956 && (info->
957 populated_ranks_mask[channel] &
958 5) != 5) {
959 if ((info->
960 spd[channel][slot]
961 [REFERENCE_RAW_CARD_USED] &
962 0x1F) == 3) {
963 a = u16_ffd1178[0]
964 [info->
965 clock_speed_index];
966 b = u16_fe0eb8[0][info->
967 clock_speed_index];
968 } else
969 if ((info->
970 spd[channel][slot]
971 [REFERENCE_RAW_CARD_USED]
972 & 0x1F) == 5) {
973 a = u16_ffd1178[1]
974 [info->
975 clock_speed_index];
976 b = u16_fe0eb8[1][info->
977 clock_speed_index];
978 }
979 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100980 min_of_unk_2 = MIN(min_of_unk_2, a);
981 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100982 if (rank == 0) {
983 sum += a;
984 count++;
985 }
986 {
987 int t;
988 t = b +
989 u8_FFFD0EF8[channel]
990 [extended_silicon_revision]
991 [info->
992 mode4030[channel]][info->
993 clock_speed_index];
994 if (unk1 >= t)
995 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100996 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100997 unk1 - t);
998 }
999 }
1000 {
1001 int t =
1002 u8_FFFD17E0[channel]
1003 [extended_silicon_revision][info->
1004 mode4030
1005 [channel]]
1006 [info->clock_speed_index] + min_of_unk_2;
1007 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001008 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001009 }
1010 }
1011
Jacob Garber64fb4a32019-06-10 17:29:18 -06001012 if (count == 0)
1013 die("No memory ranks found for channel %u\n", channel);
1014
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001015 info->avg4044[channel] = sum / count;
1016 info->max4048[channel] = max_of_unk;
1017 }
1018}
1019
1020static void jedec_read(struct raminfo *info,
1021 int channel, int slot, int rank,
1022 int total_rank, u8 addr3, unsigned int value)
1023{
1024 /* Handle mirrored mapping. */
1025 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001026 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1027 ((addr3 >> 1) & 0x10);
1028 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1029 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001030
1031 /* Handle mirrored mapping. */
1032 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1033 value =
1034 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1035 << 1);
1036
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001037 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001038
Felix Held04be2dd2018-07-29 04:53:22 +02001039 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1040 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001041
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001042 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001043}
1044
1045enum {
1046 MR1_RZQ12 = 512,
1047 MR1_RZQ2 = 64,
1048 MR1_RZQ4 = 4,
1049 MR1_ODS34OHM = 2
1050};
1051
1052enum {
1053 MR0_BT_INTERLEAVED = 8,
1054 MR0_DLL_RESET_ON = 256
1055};
1056
1057enum {
1058 MR2_RTT_WR_DISABLED = 0,
1059 MR2_RZQ2 = 1 << 10
1060};
1061
1062static void jedec_init(struct raminfo *info)
1063{
1064 int write_recovery;
1065 int channel, slot, rank;
1066 int total_rank;
1067 int dll_on;
1068 int self_refresh_temperature;
1069 int auto_self_refresh;
1070
1071 auto_self_refresh = 1;
1072 self_refresh_temperature = 1;
1073 if (info->board_lane_delay[3] <= 10) {
1074 if (info->board_lane_delay[3] <= 8)
1075 write_recovery = info->board_lane_delay[3] - 4;
1076 else
1077 write_recovery = 5;
1078 } else {
1079 write_recovery = 6;
1080 }
1081 FOR_POPULATED_RANKS {
1082 auto_self_refresh &=
1083 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1084 self_refresh_temperature &=
1085 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1086 }
1087 if (auto_self_refresh == 1)
1088 self_refresh_temperature = 0;
1089
1090 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1091 || (info->populated_ranks[0][0][0]
1092 && info->populated_ranks[0][1][0])
1093 || (info->populated_ranks[1][0][0]
1094 && info->populated_ranks[1][1][0]));
1095
1096 total_rank = 0;
1097
1098 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1099 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1100 int rzq_reg58e;
1101
1102 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1103 rzq_reg58e = 64;
1104 rtt = MR1_RZQ2;
1105 if (info->clock_speed_index != 0) {
1106 rzq_reg58e = 4;
1107 if (info->populated_ranks_mask[channel] == 3)
1108 rtt = MR1_RZQ4;
1109 }
1110 } else {
1111 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1112 rtt = MR1_RZQ12;
1113 rzq_reg58e = 64;
1114 rtt_wr = MR2_RZQ2;
1115 } else {
1116 rzq_reg58e = 4;
1117 rtt = MR1_RZQ4;
1118 }
1119 }
1120
Felix Held04be2dd2018-07-29 04:53:22 +02001121 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1122 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1123 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1124 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1125 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001126
1127 for (slot = 0; slot < NUM_SLOTS; slot++)
1128 for (rank = 0; rank < NUM_RANKS; rank++)
1129 if (info->populated_ranks[channel][slot][rank]) {
1130 jedec_read(info, channel, slot, rank,
1131 total_rank, 0x28,
1132 rtt_wr | (info->
1133 clock_speed_index
1134 << 3)
1135 | (auto_self_refresh << 6) |
1136 (self_refresh_temperature <<
1137 7));
1138 jedec_read(info, channel, slot, rank,
1139 total_rank, 0x38, 0);
1140 jedec_read(info, channel, slot, rank,
1141 total_rank, 0x18,
1142 rtt | MR1_ODS34OHM);
1143 jedec_read(info, channel, slot, rank,
1144 total_rank, 6,
1145 (dll_on << 12) |
1146 (write_recovery << 9)
1147 | ((info->cas_latency - 4) <<
1148 4) | MR0_BT_INTERLEAVED |
1149 MR0_DLL_RESET_ON);
1150 total_rank++;
1151 }
1152 }
1153}
1154
1155static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1156{
Martin Roth468d02c2019-10-23 21:44:42 -06001157 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001158 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1159 unsigned int channel_0_non_interleaved;
1160
1161 FOR_ALL_RANKS {
1162 if (info->populated_ranks[channel][slot][rank]) {
1163 total_mb[channel] +=
1164 pre_jedec ? 256 : (256 << info->
1165 density[channel][slot] >> info->
1166 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001167 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1168 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1169 (info->is_x16_module[channel][slot] |
1170 ((info->density[channel][slot] + 1) << 1))) |
1171 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 }
Felix Held04be2dd2018-07-29 04:53:22 +02001173 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1174 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001175 }
1176
1177 info->total_memory_mb = total_mb[0] + total_mb[1];
1178
1179 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001180 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001181 info->non_interleaved_part_mb =
1182 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1183 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001184 MCHBAR32(0x100) = channel_0_non_interleaved |
1185 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001186 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001187 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001188}
1189
1190static void program_board_delay(struct raminfo *info)
1191{
1192 int cas_latency_shift;
1193 int some_delay_ns;
1194 int some_delay_3_half_cycles;
1195
Martin Roth468d02c2019-10-23 21:44:42 -06001196 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001197 int high_multiplier;
1198 int lane_3_delay;
1199 int cas_latency_derived;
1200
1201 high_multiplier = 0;
1202 some_delay_ns = 200;
1203 some_delay_3_half_cycles = 4;
1204 cas_latency_shift = info->silicon_revision == 0
1205 || info->silicon_revision == 1 ? 1 : 0;
1206 if (info->revision < 8) {
1207 some_delay_ns = 600;
1208 cas_latency_shift = 0;
1209 }
1210 {
1211 int speed_bit;
1212 speed_bit =
1213 ((info->clock_speed_index > 1
1214 || (info->silicon_revision != 2
1215 && info->silicon_revision != 3))) ^ (info->revision >=
1216 0x10);
1217 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1218 3, 1);
1219 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1220 3, 1);
1221 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1222 && (info->silicon_revision == 2
1223 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001224 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001225 }
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1227 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001228
Felix Held04be2dd2018-07-29 04:53:22 +02001229 MCHBAR8(0x124) = info->board_lane_delay[4] +
1230 ((frequency_01(info) + 999) / 1000);
1231 MCHBAR16(0x125) = 0x1360;
1232 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001233 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001234 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001235 high_multiplier = 1;
1236 some_delay_2_half_cycles = ps_to_halfcycles(info,
1237 ((3 *
1238 fsbcycle_ps(info))
1239 >> 1) +
1240 (halfcycle_ps(info)
1241 *
1242 reg178_min[info->
1243 clock_speed_index]
1244 >> 6)
1245 +
1246 4 *
1247 halfcycle_ps(info)
1248 + 2230);
1249 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001250 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001251 (frequency_11(info) * 2) * (28 -
1252 some_delay_2_half_cycles) /
1253 (frequency_11(info) * 2 -
1254 4 * (info->fsb_frequency))) >> 3, 7);
1255 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001256 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001257 some_delay_3_half_cycles = 3;
1258 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001259 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1260 MCHBAR32(0x224 + (channel << 10)) =
1261 (info->max_slots_used_in_channel - 1) |
1262 ((info->cas_latency - 5 - info->clock_speed_index)
1263 << 21) | ((info->max_slots_used_in_channel +
1264 info->cas_latency - cas_latency_shift - 4) << 16) |
1265 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1266 ((info->cas_latency - info->clock_speed_index +
1267 info->max_slots_used_in_channel - 6) << 8);
1268 MCHBAR32(0x228 + (channel << 10)) =
1269 info->max_slots_used_in_channel;
1270 MCHBAR8(0x239 + (channel << 10)) = 32;
1271 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1272 (some_delay_3_half_cycles << 25) | 0x840000;
1273 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1274 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1275 MCHBAR32(0x24c + (channel << 10)) =
1276 ((!!info->clock_speed_index) << 17) |
1277 (((2 + info->clock_speed_index -
1278 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279
Felix Held04be2dd2018-07-29 04:53:22 +02001280 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1281 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1282 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001283
1284 write_500(info, channel,
1285 ((!info->populated_ranks[channel][1][1])
1286 | (!info->populated_ranks[channel][1][0] << 1)
1287 | (!info->populated_ranks[channel][0][1] << 2)
1288 | (!info->populated_ranks[channel][0][0] << 3)),
1289 0x4c9, 4, 1);
1290 }
1291
Felix Held22ca8cb2018-07-29 05:09:44 +02001292 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001293 {
1294 u8 freq_divisor = 2;
1295 if (info->fsb_frequency == frequency_11(info))
1296 freq_divisor = 3;
1297 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1298 freq_divisor = 1;
1299 else
1300 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001301 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001302 }
1303
1304 if (info->board_lane_delay[3] <= 10) {
1305 if (info->board_lane_delay[3] <= 8)
1306 lane_3_delay = info->board_lane_delay[3];
1307 else
1308 lane_3_delay = 10;
1309 } else {
1310 lane_3_delay = 12;
1311 }
1312 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1313 if (info->clock_speed_index > 1)
1314 cas_latency_derived++;
1315 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001316 MCHBAR32(0x240 + (channel << 10)) =
1317 ((info->clock_speed_index == 0) * 0x11000) |
1318 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1319 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001320 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1321 0x609, 6, 1);
1322 write_500(info, channel,
1323 info->clock_speed_index + 2 * info->cas_latency - 7,
1324 0x601, 6, 1);
1325
Felix Held04be2dd2018-07-29 04:53:22 +02001326 MCHBAR32(0x250 + (channel << 10)) =
1327 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1328 (info->board_lane_delay[7] << 2) |
1329 (info->board_lane_delay[4] << 16) |
1330 (info->board_lane_delay[1] << 25) |
1331 (info->board_lane_delay[1] << 29) | 1;
1332 MCHBAR32(0x254 + (channel << 10)) =
1333 (info->board_lane_delay[1] >> 3) |
1334 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1335 0x80 | (info->board_lane_delay[6] << 1) |
1336 (info->board_lane_delay[2] << 28) |
1337 (cas_latency_derived << 16) | 0x4700000;
1338 MCHBAR32(0x258 + (channel << 10)) =
1339 ((info->board_lane_delay[5] + info->clock_speed_index +
1340 9) << 12) | ((info->clock_speed_index -
1341 info->cas_latency + 12) << 8) |
1342 (info->board_lane_delay[2] << 17) |
1343 (info->board_lane_delay[4] << 24) | 0x47;
1344 MCHBAR32(0x25c + (channel << 10)) =
1345 (info->board_lane_delay[1] << 1) |
1346 (info->board_lane_delay[0] << 8) | 0x1da50000;
1347 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1348 MCHBAR8(0x5f8 + (channel << 10)) =
1349 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001350 }
1351
1352 program_modules_memory_map(info, 1);
1353
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001354 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001355 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1356 MCHBAR16_OR(0x612, 0x100);
1357 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001358 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001359 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001360 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001361 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001362 }
1363}
1364
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001365#define DEFAULT_PCI_MMIO_SIZE 2048
1366#define HOST_BRIDGE PCI_DEVFN(0, 0)
1367
1368static unsigned int get_mmio_size(void)
1369{
1370 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001371 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001372
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001373 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001374 if (dev)
1375 cfg = dev->chip_info;
1376
1377 /* If this is zero, it just means devicetree.cb didn't set it */
1378 if (!cfg || cfg->pci_mmio_size == 0)
1379 return DEFAULT_PCI_MMIO_SIZE;
1380 else
1381 return cfg->pci_mmio_size;
1382}
1383
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001384static void program_total_memory_map(struct raminfo *info)
1385{
Angel Pons9333b742020-07-22 16:04:15 +02001386 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001388 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001389 unsigned int uma_base_igd;
1390 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001391 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001392 int memory_remap;
1393 unsigned int memory_map[8];
1394 int i;
1395 unsigned int current_limit;
1396 unsigned int tseg_base;
1397 int uma_size_igd = 0, uma_size_gtt = 0;
1398
1399 memset(memory_map, 0, sizeof(memory_map));
1400
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001402 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 gav(t);
1404 const int uma_sizes_gtt[16] =
1405 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1406 /* Igd memory */
1407 const int uma_sizes_igd[16] = {
1408 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1409 256, 512
1410 };
1411
1412 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1413 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1414 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001416 mmio_size = get_mmio_size();
1417
Angel Pons9333b742020-07-22 16:04:15 +02001418 tom = info->total_memory_mb;
1419 if (tom == 4096)
1420 tom = 4032;
1421 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1422 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1423 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001424 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001425 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001427 remap_base = MAX(4096, touud);
1428 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 }
Angel Pons9333b742020-07-22 16:04:15 +02001430 if (touud > 4096)
1431 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001432 quickpath_reserved = 0;
1433
Angel Pons3ab19b32020-07-22 16:29:54 +02001434 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001435
Jacob Garber975a7e32019-06-10 16:32:47 -06001436 gav(t);
1437
1438 if (t & 0x800) {
1439 u32 shift = t >> 20;
1440 if (shift == 0)
1441 die("Quickpath value is 0\n");
1442 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001444
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001446 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447
Angel Pons9333b742020-07-22 16:04:15 +02001448 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449 uma_base_gtt = uma_base_igd - uma_size_gtt;
1450 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1451 if (!memory_remap)
1452 tseg_base -= quickpath_reserved;
1453 tseg_base = ALIGN_DOWN(tseg_base, 8);
1454
Angel Pons16fe1e02020-07-22 16:12:33 +02001455 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1456 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001458 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1459 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001461 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462
1463 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001464 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1465 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001467 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001468
1469 current_limit = 0;
1470 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1471 memory_map[1] = 4096;
1472 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001473 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001474 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001475 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1476 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001477 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001478 }
1479}
1480
1481static void collect_system_info(struct raminfo *info)
1482{
1483 u32 capid0[3];
1484 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001485 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001486
Angel Ponsb600d412021-01-16 16:33:48 +01001487 for (i = 0; i < 3; i++) {
1488 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1489 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1490 }
1491 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1492 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1493 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1494
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001495 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1496
1497 if ((capid0[1] >> 11) & 1)
1498 info->uma_enabled = 0;
1499 else
1500 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001501 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001502 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1503 info->silicon_revision = 0;
1504
1505 if (capid0[2] & 2) {
1506 info->silicon_revision = 0;
1507 info->max_supported_clock_speed_index = 2;
1508 for (channel = 0; channel < NUM_CHANNELS; channel++)
1509 if (info->populated_ranks[channel][0][0]
1510 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1511 3) {
1512 info->silicon_revision = 2;
1513 info->max_supported_clock_speed_index = 1;
1514 }
1515 } else {
1516 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1517 case 1:
1518 case 2:
1519 info->silicon_revision = 3;
1520 break;
1521 case 3:
1522 info->silicon_revision = 0;
1523 break;
1524 case 0:
1525 info->silicon_revision = 2;
1526 break;
1527 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001528 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001529 case 0x40:
1530 info->silicon_revision = 0;
1531 break;
1532 case 0x48:
1533 info->silicon_revision = 1;
1534 break;
1535 }
1536 }
1537}
1538
1539static void write_training_data(struct raminfo *info)
1540{
1541 int tm, channel, slot, rank, lane;
1542 if (info->revision < 8)
1543 return;
1544
1545 for (tm = 0; tm < 4; tm++)
1546 for (channel = 0; channel < NUM_CHANNELS; channel++)
1547 for (slot = 0; slot < NUM_SLOTS; slot++)
1548 for (rank = 0; rank < NUM_RANKS; rank++)
1549 for (lane = 0; lane < 9; lane++)
1550 write_500(info, channel,
1551 info->
1552 cached_training->
1553 lane_timings[tm]
1554 [channel][slot][rank]
1555 [lane],
1556 get_timing_register_addr
1557 (lane, tm, slot,
1558 rank), 9, 0);
1559 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1560 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1561}
1562
1563static void dump_timings(struct raminfo *info)
1564{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001565 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001566 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001567 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001568 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 slot, rank);
1570 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001573 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 read_500(info, channel,
1575 get_timing_register_addr
1576 (lane, i, slot, rank),
1577 9),
1578 info->training.
1579 lane_timings[i][channel][slot][rank]
1580 [lane]);
1581 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001582 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 }
1584 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001585 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001587 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589}
1590
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001591/* Read timings and other registers that need to be restored verbatim and
1592 put them to CBMEM.
1593 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594static void save_timings(struct raminfo *info)
1595{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001596 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597 int channel, slot, rank, lane, i;
1598
1599 train = info->training;
1600 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1601 for (i = 0; i < 4; i++)
1602 train.lane_timings[i][channel][slot][rank][lane] =
1603 read_500(info, channel,
1604 get_timing_register_addr(lane, i, slot,
1605 rank), 9);
1606 train.reg_178 = read_1d0(0x178, 7);
1607 train.reg_10b = read_1d0(0x10b, 6);
1608
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001609 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1610 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001611 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612 train.reg274265[channel][0] = reg32 >> 16;
1613 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001614 train.reg274265[channel][2] =
1615 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001616 }
Felix Held04be2dd2018-07-29 04:53:22 +02001617 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1618 train.reg_6dc = MCHBAR32(0x6dc);
1619 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001620
Arthur Heymansb3282092019-04-14 17:53:28 +02001621 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1622 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001623
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001624 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001625 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1626 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001627}
1628
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629static const struct ram_training *get_cached_training(void)
1630{
Shelley Chenad9cd682020-07-23 16:10:52 -07001631 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1632 MRC_CACHE_VERSION,
1633 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001635
1636/* FIXME: add timeout. */
1637static void wait_heci_ready(void)
1638{
Felix Held04be2dd2018-07-29 04:53:22 +02001639 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1640 ;
Angel Ponseb537932020-09-14 19:18:11 +02001641
1642 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643}
1644
1645/* FIXME: add timeout. */
1646static void wait_heci_cb_avail(int len)
1647{
1648 union {
1649 struct mei_csr csr;
1650 u32 raw;
1651 } csr;
1652
Felix Held22ca8cb2018-07-29 05:09:44 +02001653 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1654 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001655
Angel Ponseb537932020-09-14 19:18:11 +02001656 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001657 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001658 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1659 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001660}
1661
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001662static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663{
1664 int len = (head->length + 3) / 4;
1665 int i;
1666
1667 wait_heci_cb_avail(len + 1);
1668
1669 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001670 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001672 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001674 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1675 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676}
1677
Angel Ponseb537932020-09-14 19:18:11 +02001678static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001679{
1680 struct mei_header head;
1681 int maxlen;
1682
1683 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001684 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001685
1686 while (len) {
1687 int cur = len;
1688 if (cur > maxlen) {
1689 cur = maxlen;
1690 head.is_complete = 0;
1691 } else
1692 head.is_complete = 1;
1693 head.length = cur;
1694 head.reserved = 0;
1695 head.client_address = clientaddress;
1696 head.host_address = hostaddress;
1697 send_heci_packet(&head, (u32 *) msg);
1698 len -= cur;
1699 msg += cur;
1700 }
1701}
1702
1703/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001704static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705{
1706 union {
1707 struct mei_csr csr;
1708 u32 raw;
1709 } csr;
1710 int i = 0;
1711
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001712 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001713 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001714 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001715 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1716
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001717 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001719 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001720 *packet_size = 0;
1721 return 0;
1722 }
Angel Ponseb537932020-09-14 19:18:11 +02001723 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724 *packet_size = 0;
1725 return -1;
1726 }
1727
Angel Ponseb537932020-09-14 19:18:11 +02001728 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001730 } while (((head->length + 3) >> 2) >
1731 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732
1733 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001734 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735 *packet_size = head->length;
1736 if (!csr.csr.ready)
1737 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001738 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739 return 0;
1740}
1741
1742/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001743static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001744{
1745 struct mei_header head;
1746 int current_position;
1747
1748 current_position = 0;
1749 while (1) {
1750 u32 current_size;
1751 current_size = *message_size - current_position;
1752 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001753 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754 &current_size) == -1)
1755 break;
1756 if (!current_size)
1757 break;
1758 current_position += current_size;
1759 if (head.is_complete) {
1760 *message_size = current_position;
1761 return 0;
1762 }
1763
1764 if (current_position >= *message_size)
1765 break;
1766 }
1767 *message_size = 0;
1768 return -1;
1769}
1770
Angel Pons55f11e22020-09-14 19:06:53 +02001771static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001772{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001773 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001774 u8 group_id;
1775 u8 command;
1776 u8 reserved;
1777 u8 result;
1778 u8 field2;
1779 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001780 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001781
1782 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1783 reply.command = 0;
1784
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001785 struct uma_message {
1786 u8 group_id;
1787 u8 cmd;
1788 u8 reserved;
1789 u8 result;
1790 u32 c2;
1791 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001792 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001793 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001794 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001795 .group_id = 0,
1796 .cmd = MKHI_SET_UMA,
1797 .reserved = 0,
1798 .result = 0,
1799 .c2 = 0x82,
1800 .heci_uma_addr = heci_uma_addr,
1801 .heci_uma_size = heci_uma_size,
1802 .c3 = 0,
1803 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001804 u32 reply_size;
1805
Angel Ponseb537932020-09-14 19:18:11 +02001806 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807
1808 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001809 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001810 return;
1811
1812 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1813 die("HECI init failed\n");
1814}
1815
1816static void setup_heci_uma(struct raminfo *info)
1817{
Angel Pons298d34d2020-09-14 18:58:53 +02001818 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001819 return;
1820
Angel Pons36592bf2020-09-14 18:52:44 +02001821 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001822 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001823 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001824 info->memory_reserved_for_heci_mb)) << 20;
1825
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001826 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001828 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001829 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001830 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001831 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001832 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001833 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001834 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001835 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836
Angel Ponsee7fb342021-01-28 14:11:55 +01001837 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001838 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001839
Angel Ponsee7fb342021-01-28 14:11:55 +01001840 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001841 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842 }
1843
Felix Held04be2dd2018-07-29 04:53:22 +02001844 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001845
Angel Pons55f11e22020-09-14 19:06:53 +02001846 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001848 pci_write_config32(HECIDEV, 0x10, 0x0);
1849 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001850}
1851
1852static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1853{
1854 int ranks_in_channel;
1855 ranks_in_channel = info->populated_ranks[channel][0][0]
1856 + info->populated_ranks[channel][0][1]
1857 + info->populated_ranks[channel][1][0]
1858 + info->populated_ranks[channel][1][1];
1859
1860 /* empty channel */
1861 if (ranks_in_channel == 0)
1862 return 1;
1863
1864 if (ranks_in_channel != ranks)
1865 return 0;
1866 /* single slot */
1867 if (info->populated_ranks[channel][0][0] !=
1868 info->populated_ranks[channel][1][0])
1869 return 1;
1870 if (info->populated_ranks[channel][0][1] !=
1871 info->populated_ranks[channel][1][1])
1872 return 1;
1873 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1874 return 0;
1875 if (info->density[channel][0] != info->density[channel][1])
1876 return 0;
1877 return 1;
1878}
1879
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001880static void read_4090(struct raminfo *info)
1881{
1882 int i, channel, slot, rank, lane;
1883 for (i = 0; i < 2; i++)
1884 for (slot = 0; slot < NUM_SLOTS; slot++)
1885 for (rank = 0; rank < NUM_RANKS; rank++)
1886 for (lane = 0; lane < 9; lane++)
1887 info->training.
1888 lane_timings[0][i][slot][rank][lane]
1889 = 32;
1890
1891 for (i = 1; i < 4; i++)
1892 for (channel = 0; channel < NUM_CHANNELS; channel++)
1893 for (slot = 0; slot < NUM_SLOTS; slot++)
1894 for (rank = 0; rank < NUM_RANKS; rank++)
1895 for (lane = 0; lane < 9; lane++) {
1896 info->training.
1897 lane_timings[i][channel]
1898 [slot][rank][lane] =
1899 read_500(info, channel,
1900 get_timing_register_addr
1901 (lane, i, slot,
1902 rank), 9)
1903 + (i == 1) * 11; // !!!!
1904 }
1905
1906}
1907
1908static u32 get_etalon2(int flip, u32 addr)
1909{
1910 const u16 invmask[] = {
1911 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1912 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1913 };
1914 u32 ret;
1915 u32 comp4 = addr / 480;
1916 addr %= 480;
1917 u32 comp1 = addr & 0xf;
1918 u32 comp2 = (addr >> 4) & 1;
1919 u32 comp3 = addr >> 5;
1920
1921 if (comp4)
1922 ret = 0x1010101 << (comp4 - 1);
1923 else
1924 ret = 0;
1925 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1926 ret = ~ret;
1927
1928 return ret;
1929}
1930
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001931static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001932{
1933 msr_t msr = {.lo = 0, .hi = 0 };
1934
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001935 wrmsr(MTRR_PHYS_BASE(3), msr);
1936 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001937}
1938
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001939static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001940{
1941 msr_t msr;
1942 msr.lo = base | MTRR_TYPE_WRPROT;
1943 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001944 wrmsr(MTRR_PHYS_BASE(3), msr);
1945 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001946 & 0xffffffff);
1947 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001948 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001949}
1950
1951static void flush_cache(u32 start, u32 size)
1952{
1953 u32 end;
1954 u32 addr;
1955
1956 end = start + (ALIGN_DOWN(size + 4096, 4096));
1957 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001958 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001959}
1960
1961static void clear_errors(void)
1962{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001963 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001964}
1965
1966static void write_testing(struct raminfo *info, int totalrank, int flip)
1967{
1968 int nwrites = 0;
1969 /* in 8-byte units. */
1970 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001971 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972
Patrick Rudolph819c2062019-11-29 19:27:37 +01001973 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001974 for (offset = 0; offset < 9 * 480; offset += 2) {
1975 write32(base + offset * 8, get_etalon2(flip, offset));
1976 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1977 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1978 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1979 nwrites += 4;
1980 if (nwrites >= 320) {
1981 clear_errors();
1982 nwrites = 0;
1983 }
1984 }
1985}
1986
1987static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1988{
1989 u8 failmask = 0;
1990 int i;
1991 int comp1, comp2, comp3;
1992 u32 failxor[2] = { 0, 0 };
1993
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001994 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995
1996 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1997 for (comp1 = 0; comp1 < 4; comp1++)
1998 for (comp2 = 0; comp2 < 60; comp2++) {
1999 u32 re[4];
2000 u32 curroffset =
2001 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2002 read128((total_rank << 28) | (curroffset << 3),
2003 (u64 *) re);
2004 failxor[0] |=
2005 get_etalon2(flip, curroffset) ^ re[0];
2006 failxor[1] |=
2007 get_etalon2(flip, curroffset) ^ re[1];
2008 failxor[0] |=
2009 get_etalon2(flip, curroffset | 1) ^ re[2];
2010 failxor[1] |=
2011 get_etalon2(flip, curroffset | 1) ^ re[3];
2012 }
2013 for (i = 0; i < 8; i++)
2014 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2015 failmask |= 1 << i;
2016 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002017 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002018 flush_cache((total_rank << 28), 1728 * 5 * 4);
2019 return failmask;
2020}
2021
2022const u32 seed1[0x18] = {
2023 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2024 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2025 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2026 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2027 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2028 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2029};
2030
2031static u32 get_seed2(int a, int b)
2032{
2033 const u32 seed2[5] = {
2034 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2035 0x5b6db6db,
2036 };
2037 u32 r;
2038 r = seed2[(a + (a >= 10)) / 5];
2039 return b ? ~r : r;
2040}
2041
2042static int make_shift(int comp2, int comp5, int x)
2043{
2044 const u8 seed3[32] = {
2045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2046 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2047 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2048 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2049 };
2050
2051 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2052}
2053
2054static u32 get_etalon(int flip, u32 addr)
2055{
2056 u32 mask_byte = 0;
2057 int comp1 = (addr >> 1) & 1;
2058 int comp2 = (addr >> 3) & 0x1f;
2059 int comp3 = (addr >> 8) & 0xf;
2060 int comp4 = (addr >> 12) & 0xf;
2061 int comp5 = (addr >> 16) & 0x1f;
2062 u32 mask_bit = ~(0x10001 << comp3);
2063 u32 part1;
2064 u32 part2;
2065 int byte;
2066
2067 part2 =
2068 ((seed1[comp5] >>
2069 make_shift(comp2, comp5,
2070 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2071 part1 =
2072 ((seed1[comp5] >>
2073 make_shift(comp2, comp5,
2074 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2075
2076 for (byte = 0; byte < 4; byte++)
2077 if ((get_seed2(comp5, comp4) >>
2078 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2079 mask_byte |= 0xff << (8 * byte);
2080
2081 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2082 (comp3 + 16));
2083}
2084
2085static void
2086write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2087 char flip)
2088{
2089 int i;
2090 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002091 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2092 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002093}
2094
2095static u8
2096check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2097 char flip)
2098{
2099 u8 failmask = 0;
2100 u32 failxor[2];
2101 int i;
2102 int comp1, comp2, comp3;
2103
2104 failxor[0] = 0;
2105 failxor[1] = 0;
2106
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002107 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002108 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2109 for (comp1 = 0; comp1 < 16; comp1++)
2110 for (comp2 = 0; comp2 < 64; comp2++) {
2111 u32 addr =
2112 (totalrank << 28) | (region << 25) | (block
2113 << 16)
2114 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2115 2);
2116 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002117 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002118 }
2119 for (i = 0; i < 8; i++)
2120 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2121 failmask |= 1 << i;
2122 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002123 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002124 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2125 return failmask;
2126}
2127
2128static int check_bounded(unsigned short *vals, u16 bound)
2129{
2130 int i;
2131
2132 for (i = 0; i < 8; i++)
2133 if (vals[i] < bound)
2134 return 0;
2135 return 1;
2136}
2137
2138enum state {
2139 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2140};
2141
2142static int validate_state(enum state *in)
2143{
2144 int i;
2145 for (i = 0; i < 8; i++)
2146 if (in[i] != COMPLETE)
2147 return 0;
2148 return 1;
2149}
2150
2151static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002152do_fsm(enum state *state, u16 *counter,
2153 u8 fail_mask, int margin, int uplimit,
2154 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002155{
2156 int lane;
2157
2158 for (lane = 0; lane < 8; lane++) {
2159 int is_fail = (fail_mask >> lane) & 1;
2160 switch (state[lane]) {
2161 case BEFORE_USABLE:
2162 if (!is_fail) {
2163 counter[lane] = 1;
2164 state[lane] = AT_USABLE;
2165 break;
2166 }
2167 counter[lane] = 0;
2168 state[lane] = BEFORE_USABLE;
2169 break;
2170 case AT_USABLE:
2171 if (!is_fail) {
2172 ++counter[lane];
2173 if (counter[lane] >= margin) {
2174 state[lane] = AT_MARGIN;
2175 res_low[lane] = val - margin + 1;
2176 break;
2177 }
2178 state[lane] = 1;
2179 break;
2180 }
2181 counter[lane] = 0;
2182 state[lane] = BEFORE_USABLE;
2183 break;
2184 case AT_MARGIN:
2185 if (is_fail) {
2186 state[lane] = COMPLETE;
2187 res_high[lane] = val - 1;
2188 } else {
2189 counter[lane]++;
2190 state[lane] = AT_MARGIN;
2191 if (val == uplimit) {
2192 state[lane] = COMPLETE;
2193 res_high[lane] = uplimit;
2194 }
2195 }
2196 break;
2197 case COMPLETE:
2198 break;
2199 }
2200 }
2201}
2202
2203static void
2204train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2205 u8 total_rank, u8 reg_178, int first_run, int niter,
2206 timing_bounds_t * timings)
2207{
2208 int lane;
2209 enum state state[8];
2210 u16 count[8];
2211 u8 lower_usable[8];
2212 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002213 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002214 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002215 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002216
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002217 for (i = 0; i < 8; i++)
2218 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002219
2220 if (!first_run) {
2221 int is_all_ok = 1;
2222 for (lane = 0; lane < 8; lane++)
2223 if (timings[reg_178][channel][slot][rank][lane].
2224 smallest ==
2225 timings[reg_178][channel][slot][rank][lane].
2226 largest) {
2227 timings[reg_178][channel][slot][rank][lane].
2228 smallest = 0;
2229 timings[reg_178][channel][slot][rank][lane].
2230 largest = 0;
2231 is_all_ok = 0;
2232 }
2233 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002234 for (i = 0; i < 8; i++)
2235 state[i] = COMPLETE;
2236 }
2237 }
2238
2239 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2240 u8 failmask = 0;
2241 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2242 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2243 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002244 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002245 do_fsm(state, count, failmask, 5, 47, lower_usable,
2246 upper_usable, reg1b3);
2247 }
2248
2249 if (reg1b3) {
2250 write_1d0(0, 0x1b3, 6, 1);
2251 write_1d0(0, 0x1a3, 6, 1);
2252 for (lane = 0; lane < 8; lane++) {
2253 if (state[lane] == COMPLETE) {
2254 timings[reg_178][channel][slot][rank][lane].
2255 smallest =
2256 lower_usable[lane] +
2257 (info->training.
2258 lane_timings[0][channel][slot][rank][lane]
2259 & 0x3F) - 32;
2260 timings[reg_178][channel][slot][rank][lane].
2261 largest =
2262 upper_usable[lane] +
2263 (info->training.
2264 lane_timings[0][channel][slot][rank][lane]
2265 & 0x3F) - 32;
2266 }
2267 }
2268 }
2269
2270 if (!first_run) {
2271 for (lane = 0; lane < 8; lane++)
2272 if (state[lane] == COMPLETE) {
2273 write_500(info, channel,
2274 timings[reg_178][channel][slot][rank]
2275 [lane].smallest,
2276 get_timing_register_addr(lane, 0,
2277 slot, rank),
2278 9, 1);
2279 write_500(info, channel,
2280 timings[reg_178][channel][slot][rank]
2281 [lane].smallest +
2282 info->training.
2283 lane_timings[1][channel][slot][rank]
2284 [lane]
2285 -
2286 info->training.
2287 lane_timings[0][channel][slot][rank]
2288 [lane], get_timing_register_addr(lane,
2289 1,
2290 slot,
2291 rank),
2292 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002293 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002294 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002295 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296
2297 do {
2298 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002299 for (i = 0; i < niter; i++) {
2300 if (failmask == 0xFF)
2301 break;
2302 failmask |=
2303 check_testing_type2(info, total_rank, 2, i,
2304 0);
2305 failmask |=
2306 check_testing_type2(info, total_rank, 3, i,
2307 1);
2308 }
Felix Held04be2dd2018-07-29 04:53:22 +02002309 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002310 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002311 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002312 if ((1 << lane) & failmask) {
2313 if (timings[reg_178][channel]
2314 [slot][rank][lane].
2315 largest <=
2316 timings[reg_178][channel]
2317 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002318 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002319 [lane] = -1;
2320 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002321 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 [lane] = 0;
2323 timings[reg_178]
2324 [channel][slot]
2325 [rank][lane].
2326 smallest++;
2327 write_500(info, channel,
2328 timings
2329 [reg_178]
2330 [channel]
2331 [slot][rank]
2332 [lane].
2333 smallest,
2334 get_timing_register_addr
2335 (lane, 0,
2336 slot, rank),
2337 9, 1);
2338 write_500(info, channel,
2339 timings
2340 [reg_178]
2341 [channel]
2342 [slot][rank]
2343 [lane].
2344 smallest +
2345 info->
2346 training.
2347 lane_timings
2348 [1][channel]
2349 [slot][rank]
2350 [lane]
2351 -
2352 info->
2353 training.
2354 lane_timings
2355 [0][channel]
2356 [slot][rank]
2357 [lane],
2358 get_timing_register_addr
2359 (lane, 1,
2360 slot, rank),
2361 9, 1);
2362 }
2363 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002364 num_successfully_checked[lane]
2365 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002366 }
2367 }
Felix Held04be2dd2018-07-29 04:53:22 +02002368 while (!check_bounded(num_successfully_checked, 2))
2369 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002370
2371 for (lane = 0; lane < 8; lane++)
2372 if (state[lane] == COMPLETE) {
2373 write_500(info, channel,
2374 timings[reg_178][channel][slot][rank]
2375 [lane].largest,
2376 get_timing_register_addr(lane, 0,
2377 slot, rank),
2378 9, 1);
2379 write_500(info, channel,
2380 timings[reg_178][channel][slot][rank]
2381 [lane].largest +
2382 info->training.
2383 lane_timings[1][channel][slot][rank]
2384 [lane]
2385 -
2386 info->training.
2387 lane_timings[0][channel][slot][rank]
2388 [lane], get_timing_register_addr(lane,
2389 1,
2390 slot,
2391 rank),
2392 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002393 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002394 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002395 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002396
2397 do {
2398 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399 for (i = 0; i < niter; i++) {
2400 if (failmask == 0xFF)
2401 break;
2402 failmask |=
2403 check_testing_type2(info, total_rank, 2, i,
2404 0);
2405 failmask |=
2406 check_testing_type2(info, total_rank, 3, i,
2407 1);
2408 }
2409
Felix Held04be2dd2018-07-29 04:53:22 +02002410 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002411 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002412 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002413 if ((1 << lane) & failmask) {
2414 if (timings[reg_178][channel]
2415 [slot][rank][lane].
2416 largest <=
2417 timings[reg_178][channel]
2418 [slot][rank][lane].
2419 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002420 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 [lane] = -1;
2422 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002423 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002424 [lane] = 0;
2425 timings[reg_178]
2426 [channel][slot]
2427 [rank][lane].
2428 largest--;
2429 write_500(info, channel,
2430 timings
2431 [reg_178]
2432 [channel]
2433 [slot][rank]
2434 [lane].
2435 largest,
2436 get_timing_register_addr
2437 (lane, 0,
2438 slot, rank),
2439 9, 1);
2440 write_500(info, channel,
2441 timings
2442 [reg_178]
2443 [channel]
2444 [slot][rank]
2445 [lane].
2446 largest +
2447 info->
2448 training.
2449 lane_timings
2450 [1][channel]
2451 [slot][rank]
2452 [lane]
2453 -
2454 info->
2455 training.
2456 lane_timings
2457 [0][channel]
2458 [slot][rank]
2459 [lane],
2460 get_timing_register_addr
2461 (lane, 1,
2462 slot, rank),
2463 9, 1);
2464 }
2465 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002466 num_successfully_checked[lane]
2467 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002468 }
2469 }
2470 }
Felix Held04be2dd2018-07-29 04:53:22 +02002471 while (!check_bounded(num_successfully_checked, 3))
2472 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002473
2474 for (lane = 0; lane < 8; lane++) {
2475 write_500(info, channel,
2476 info->training.
2477 lane_timings[0][channel][slot][rank][lane],
2478 get_timing_register_addr(lane, 0, slot, rank),
2479 9, 1);
2480 write_500(info, channel,
2481 info->training.
2482 lane_timings[1][channel][slot][rank][lane],
2483 get_timing_register_addr(lane, 1, slot, rank),
2484 9, 1);
2485 if (timings[reg_178][channel][slot][rank][lane].
2486 largest <=
2487 timings[reg_178][channel][slot][rank][lane].
2488 smallest) {
2489 timings[reg_178][channel][slot][rank][lane].
2490 largest = 0;
2491 timings[reg_178][channel][slot][rank][lane].
2492 smallest = 0;
2493 }
2494 }
2495 }
2496}
2497
2498static void set_10b(struct raminfo *info, u8 val)
2499{
2500 int channel;
2501 int slot, rank;
2502 int lane;
2503
2504 if (read_1d0(0x10b, 6) == val)
2505 return;
2506
2507 write_1d0(val, 0x10b, 6, 1);
2508
2509 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2510 u16 reg_500;
2511 reg_500 = read_500(info, channel,
2512 get_timing_register_addr(lane, 0, slot,
2513 rank), 9);
2514 if (val == 1) {
2515 if (lut16[info->clock_speed_index] <= reg_500)
2516 reg_500 -= lut16[info->clock_speed_index];
2517 else
2518 reg_500 = 0;
2519 } else {
2520 reg_500 += lut16[info->clock_speed_index];
2521 }
2522 write_500(info, channel, reg_500,
2523 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2524 }
2525}
2526
2527static void set_ecc(int onoff)
2528{
2529 int channel;
2530 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2531 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002532 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002533 if (onoff)
2534 t |= 1;
2535 else
2536 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002537 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002538 }
2539}
2540
2541static void set_178(u8 val)
2542{
2543 if (val >= 31)
2544 val = val - 31;
2545 else
2546 val = 63 - val;
2547
2548 write_1d0(2 * val, 0x178, 7, 1);
2549}
2550
2551static void
2552write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2553 int type)
2554{
2555 int lane;
2556
2557 for (lane = 0; lane < 8; lane++)
2558 write_500(info, channel,
2559 info->training.
2560 lane_timings[type][channel][slot][rank][lane],
2561 get_timing_register_addr(lane, type, slot, rank), 9,
2562 0);
2563}
2564
2565static void
2566try_timing_offsets(struct raminfo *info, int channel,
2567 int slot, int rank, int totalrank)
2568{
2569 u16 count[8];
2570 enum state state[8];
2571 u8 lower_usable[8], upper_usable[8];
2572 int lane;
2573 int i;
2574 int flip = 1;
2575 int timing_offset;
2576
2577 for (i = 0; i < 8; i++)
2578 state[i] = BEFORE_USABLE;
2579
2580 memset(count, 0, sizeof(count));
2581
2582 for (lane = 0; lane < 8; lane++)
2583 write_500(info, channel,
2584 info->training.
2585 lane_timings[2][channel][slot][rank][lane] + 32,
2586 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2587
2588 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2589 timing_offset++) {
2590 u8 failmask;
2591 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2592 failmask = 0;
2593 for (i = 0; i < 2 && failmask != 0xff; i++) {
2594 flip = !flip;
2595 write_testing(info, totalrank, flip);
2596 failmask |= check_testing(info, totalrank, flip);
2597 }
2598 do_fsm(state, count, failmask, 10, 63, lower_usable,
2599 upper_usable, timing_offset);
2600 }
2601 write_1d0(0, 0x1bb, 6, 1);
2602 dump_timings(info);
2603 if (!validate_state(state))
2604 die("Couldn't discover DRAM timings (1)\n");
2605
2606 for (lane = 0; lane < 8; lane++) {
2607 u8 bias = 0;
2608
2609 if (info->silicon_revision) {
2610 int usable_length;
2611
2612 usable_length = upper_usable[lane] - lower_usable[lane];
2613 if (usable_length >= 20) {
2614 bias = usable_length / 2 - 10;
2615 if (bias >= 2)
2616 bias = 2;
2617 }
2618 }
2619 write_500(info, channel,
2620 info->training.
2621 lane_timings[2][channel][slot][rank][lane] +
2622 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2623 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2624 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2625 info->training.lane_timings[2][channel][slot][rank][lane] +
2626 lower_usable[lane];
2627 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2628 info->training.lane_timings[2][channel][slot][rank][lane] +
2629 upper_usable[lane];
2630 info->training.timing2_offset[channel][slot][rank][lane] =
2631 info->training.lane_timings[2][channel][slot][rank][lane];
2632 }
2633}
2634
2635static u8
2636choose_training(struct raminfo *info, int channel, int slot, int rank,
2637 int lane, timing_bounds_t * timings, u8 center_178)
2638{
2639 u16 central_weight;
2640 u16 side_weight;
2641 unsigned int sum = 0, count = 0;
2642 u8 span;
2643 u8 lower_margin, upper_margin;
2644 u8 reg_178;
2645 u8 result;
2646
2647 span = 12;
2648 central_weight = 20;
2649 side_weight = 20;
2650 if (info->silicon_revision == 1 && channel == 1) {
2651 central_weight = 5;
2652 side_weight = 20;
2653 if ((info->
2654 populated_ranks_mask[1] ^ (info->
2655 populated_ranks_mask[1] >> 2)) &
2656 1)
2657 span = 18;
2658 }
2659 if ((info->populated_ranks_mask[0] & 5) == 5) {
2660 central_weight = 20;
2661 side_weight = 20;
2662 }
2663 if (info->clock_speed_index >= 2
2664 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2665 if (info->silicon_revision == 1) {
2666 switch (channel) {
2667 case 0:
2668 if (lane == 1) {
2669 central_weight = 10;
2670 side_weight = 20;
2671 }
2672 break;
2673 case 1:
2674 if (lane == 6) {
2675 side_weight = 5;
2676 central_weight = 20;
2677 }
2678 break;
2679 }
2680 }
2681 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2682 side_weight = 5;
2683 central_weight = 20;
2684 }
2685 }
2686 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2687 reg_178 += span) {
2688 u8 smallest;
2689 u8 largest;
2690 largest = timings[reg_178][channel][slot][rank][lane].largest;
2691 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2692 if (largest - smallest + 1 >= 5) {
2693 unsigned int weight;
2694 if (reg_178 == center_178)
2695 weight = central_weight;
2696 else
2697 weight = side_weight;
2698 sum += weight * (largest + smallest);
2699 count += weight;
2700 }
2701 }
2702 dump_timings(info);
2703 if (count == 0)
2704 die("Couldn't discover DRAM timings (2)\n");
2705 result = sum / (2 * count);
2706 lower_margin =
2707 result - timings[center_178][channel][slot][rank][lane].smallest;
2708 upper_margin =
2709 timings[center_178][channel][slot][rank][lane].largest - result;
2710 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002711 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002712 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002713 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002714 return result;
2715}
2716
2717#define STANDARD_MIN_MARGIN 5
2718
2719static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2720{
2721 u16 margin[64];
2722 int lane, rank, slot, channel;
2723 u8 reg178;
2724 int count = 0, sum = 0;
2725
2726 for (reg178 = reg178_min[info->clock_speed_index];
2727 reg178 < reg178_max[info->clock_speed_index];
2728 reg178 += reg178_step[info->clock_speed_index]) {
2729 margin[reg178] = -1;
2730 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2731 int curmargin =
2732 timings[reg178][channel][slot][rank][lane].largest -
2733 timings[reg178][channel][slot][rank][lane].
2734 smallest + 1;
2735 if (curmargin < margin[reg178])
2736 margin[reg178] = curmargin;
2737 }
2738 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2739 u16 weight;
2740 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2741 sum += weight * reg178;
2742 count += weight;
2743 }
2744 }
2745 dump_timings(info);
2746 if (count == 0)
2747 die("Couldn't discover DRAM timings (3)\n");
2748
2749 u8 threshold;
2750
2751 for (threshold = 30; threshold >= 5; threshold--) {
2752 int usable_length = 0;
2753 int smallest_fount = 0;
2754 for (reg178 = reg178_min[info->clock_speed_index];
2755 reg178 < reg178_max[info->clock_speed_index];
2756 reg178 += reg178_step[info->clock_speed_index])
2757 if (margin[reg178] >= threshold) {
2758 usable_length +=
2759 reg178_step[info->clock_speed_index];
2760 info->training.reg178_largest =
2761 reg178 -
2762 2 * reg178_step[info->clock_speed_index];
2763
2764 if (!smallest_fount) {
2765 smallest_fount = 1;
2766 info->training.reg178_smallest =
2767 reg178 +
2768 reg178_step[info->
2769 clock_speed_index];
2770 }
2771 }
2772 if (usable_length >= 0x21)
2773 break;
2774 }
2775
2776 return sum / count;
2777}
2778
2779static int check_cached_sanity(struct raminfo *info)
2780{
2781 int lane;
2782 int slot, rank;
2783 int channel;
2784
2785 if (!info->cached_training)
2786 return 0;
2787
2788 for (channel = 0; channel < NUM_CHANNELS; channel++)
2789 for (slot = 0; slot < NUM_SLOTS; slot++)
2790 for (rank = 0; rank < NUM_RANKS; rank++)
2791 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2792 u16 cached_value, estimation_value;
2793 cached_value =
2794 info->cached_training->
2795 lane_timings[1][channel][slot][rank]
2796 [lane];
2797 if (cached_value >= 0x18
2798 && cached_value <= 0x1E7) {
2799 estimation_value =
2800 info->training.
2801 lane_timings[1][channel]
2802 [slot][rank][lane];
2803 if (estimation_value <
2804 cached_value - 24)
2805 return 0;
2806 if (estimation_value >
2807 cached_value + 24)
2808 return 0;
2809 }
2810 }
2811 return 1;
2812}
2813
2814static int try_cached_training(struct raminfo *info)
2815{
2816 u8 saved_243[2];
2817 u8 tm;
2818
2819 int channel, slot, rank, lane;
2820 int flip = 1;
2821 int i, j;
2822
2823 if (!check_cached_sanity(info))
2824 return 0;
2825
2826 info->training.reg178_center = info->cached_training->reg178_center;
2827 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2828 info->training.reg178_largest = info->cached_training->reg178_largest;
2829 memcpy(&info->training.timing_bounds,
2830 &info->cached_training->timing_bounds,
2831 sizeof(info->training.timing_bounds));
2832 memcpy(&info->training.timing_offset,
2833 &info->cached_training->timing_offset,
2834 sizeof(info->training.timing_offset));
2835
2836 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002837 saved_243[0] = MCHBAR8(0x243);
2838 saved_243[1] = MCHBAR8(0x643);
2839 MCHBAR8(0x243) = saved_243[0] | 2;
2840 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002841 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002842 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002843 if (read_1d0(0x10b, 6) & 1)
2844 set_10b(info, 0);
2845 for (tm = 0; tm < 2; tm++) {
2846 int totalrank;
2847
2848 set_178(tm ? info->cached_training->reg178_largest : info->
2849 cached_training->reg178_smallest);
2850
2851 totalrank = 0;
2852 /* Check timing ranges. With i == 0 we check smallest one and with
2853 i == 1 the largest bound. With j == 0 we check that on the bound
2854 it still works whereas with j == 1 we check that just outside of
2855 bound we fail.
2856 */
2857 FOR_POPULATED_RANKS_BACKWARDS {
2858 for (i = 0; i < 2; i++) {
2859 for (lane = 0; lane < 8; lane++) {
2860 write_500(info, channel,
2861 info->cached_training->
2862 timing2_bounds[channel][slot]
2863 [rank][lane][i],
2864 get_timing_register_addr(lane,
2865 3,
2866 slot,
2867 rank),
2868 9, 1);
2869
2870 if (!i)
2871 write_500(info, channel,
2872 info->
2873 cached_training->
2874 timing2_offset
2875 [channel][slot][rank]
2876 [lane],
2877 get_timing_register_addr
2878 (lane, 2, slot, rank),
2879 9, 1);
2880 write_500(info, channel,
2881 i ? info->cached_training->
2882 timing_bounds[tm][channel]
2883 [slot][rank][lane].
2884 largest : info->
2885 cached_training->
2886 timing_bounds[tm][channel]
2887 [slot][rank][lane].smallest,
2888 get_timing_register_addr(lane,
2889 0,
2890 slot,
2891 rank),
2892 9, 1);
2893 write_500(info, channel,
2894 info->cached_training->
2895 timing_offset[channel][slot]
2896 [rank][lane] +
2897 (i ? info->cached_training->
2898 timing_bounds[tm][channel]
2899 [slot][rank][lane].
2900 largest : info->
2901 cached_training->
2902 timing_bounds[tm][channel]
2903 [slot][rank][lane].
2904 smallest) - 64,
2905 get_timing_register_addr(lane,
2906 1,
2907 slot,
2908 rank),
2909 9, 1);
2910 }
2911 for (j = 0; j < 2; j++) {
2912 u8 failmask;
2913 u8 expected_failmask;
2914 char reg1b3;
2915
2916 reg1b3 = (j == 1) + 4;
2917 reg1b3 =
2918 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2919 write_1d0(reg1b3, 0x1bb, 6, 1);
2920 write_1d0(reg1b3, 0x1b3, 6, 1);
2921 write_1d0(reg1b3, 0x1a3, 6, 1);
2922
2923 flip = !flip;
2924 write_testing(info, totalrank, flip);
2925 failmask =
2926 check_testing(info, totalrank,
2927 flip);
2928 expected_failmask =
2929 j == 0 ? 0x00 : 0xff;
2930 if (failmask != expected_failmask)
2931 goto fail;
2932 }
2933 }
2934 totalrank++;
2935 }
2936 }
2937
2938 set_178(info->cached_training->reg178_center);
2939 if (info->use_ecc)
2940 set_ecc(1);
2941 write_training_data(info);
2942 write_1d0(0, 322, 3, 1);
2943 info->training = *info->cached_training;
2944
2945 write_1d0(0, 0x1bb, 6, 1);
2946 write_1d0(0, 0x1b3, 6, 1);
2947 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002948 MCHBAR8(0x243) = saved_243[0];
2949 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002950
2951 return 1;
2952
2953fail:
2954 FOR_POPULATED_RANKS {
2955 write_500_timings_type(info, channel, slot, rank, 1);
2956 write_500_timings_type(info, channel, slot, rank, 2);
2957 write_500_timings_type(info, channel, slot, rank, 3);
2958 }
2959
2960 write_1d0(0, 0x1bb, 6, 1);
2961 write_1d0(0, 0x1b3, 6, 1);
2962 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002963 MCHBAR8(0x243) = saved_243[0];
2964 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002965
2966 return 0;
2967}
2968
2969static void do_ram_training(struct raminfo *info)
2970{
2971 u8 saved_243[2];
2972 int totalrank = 0;
2973 u8 reg_178;
2974 int niter;
2975
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002976 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002977 int lane, rank, slot, channel;
2978 u8 reg178_center;
2979
2980 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002981 saved_243[0] = MCHBAR8(0x243);
2982 saved_243[1] = MCHBAR8(0x643);
2983 MCHBAR8(0x243) = saved_243[0] | 2;
2984 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002985 switch (info->clock_speed_index) {
2986 case 0:
2987 niter = 5;
2988 break;
2989 case 1:
2990 niter = 10;
2991 break;
2992 default:
2993 niter = 19;
2994 break;
2995 }
2996 set_ecc(0);
2997
2998 FOR_POPULATED_RANKS_BACKWARDS {
2999 int i;
3000
3001 write_500_timings_type(info, channel, slot, rank, 0);
3002
3003 write_testing(info, totalrank, 0);
3004 for (i = 0; i < niter; i++) {
3005 write_testing_type2(info, totalrank, 2, i, 0);
3006 write_testing_type2(info, totalrank, 3, i, 1);
3007 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003008 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003009 totalrank++;
3010 }
3011
3012 if (reg178_min[info->clock_speed_index] <
3013 reg178_max[info->clock_speed_index])
3014 memset(timings[reg178_min[info->clock_speed_index]], 0,
3015 sizeof(timings[0]) *
3016 (reg178_max[info->clock_speed_index] -
3017 reg178_min[info->clock_speed_index]));
3018 for (reg_178 = reg178_min[info->clock_speed_index];
3019 reg_178 < reg178_max[info->clock_speed_index];
3020 reg_178 += reg178_step[info->clock_speed_index]) {
3021 totalrank = 0;
3022 set_178(reg_178);
3023 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3024 for (slot = 0; slot < NUM_SLOTS; slot++)
3025 for (rank = 0; rank < NUM_RANKS; rank++) {
3026 memset(&timings[reg_178][channel][slot]
3027 [rank][0].smallest, 0, 16);
3028 if (info->
3029 populated_ranks[channel][slot]
3030 [rank]) {
3031 train_ram_at_178(info, channel,
3032 slot, rank,
3033 totalrank,
3034 reg_178, 1,
3035 niter,
3036 timings);
3037 totalrank++;
3038 }
3039 }
3040 }
3041
3042 reg178_center = choose_reg178(info, timings);
3043
3044 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3045 info->training.timing_bounds[0][channel][slot][rank][lane].
3046 smallest =
3047 timings[info->training.
3048 reg178_smallest][channel][slot][rank][lane].
3049 smallest;
3050 info->training.timing_bounds[0][channel][slot][rank][lane].
3051 largest =
3052 timings[info->training.
3053 reg178_smallest][channel][slot][rank][lane].largest;
3054 info->training.timing_bounds[1][channel][slot][rank][lane].
3055 smallest =
3056 timings[info->training.
3057 reg178_largest][channel][slot][rank][lane].smallest;
3058 info->training.timing_bounds[1][channel][slot][rank][lane].
3059 largest =
3060 timings[info->training.
3061 reg178_largest][channel][slot][rank][lane].largest;
3062 info->training.timing_offset[channel][slot][rank][lane] =
3063 info->training.lane_timings[1][channel][slot][rank][lane]
3064 -
3065 info->training.lane_timings[0][channel][slot][rank][lane] +
3066 64;
3067 }
3068
3069 if (info->silicon_revision == 1
3070 && (info->
3071 populated_ranks_mask[1] ^ (info->
3072 populated_ranks_mask[1] >> 2)) & 1) {
3073 int ranks_after_channel1;
3074
3075 totalrank = 0;
3076 for (reg_178 = reg178_center - 18;
3077 reg_178 <= reg178_center + 18; reg_178 += 18) {
3078 totalrank = 0;
3079 set_178(reg_178);
3080 for (slot = 0; slot < NUM_SLOTS; slot++)
3081 for (rank = 0; rank < NUM_RANKS; rank++) {
3082 if (info->
3083 populated_ranks[1][slot][rank]) {
3084 train_ram_at_178(info, 1, slot,
3085 rank,
3086 totalrank,
3087 reg_178, 0,
3088 niter,
3089 timings);
3090 totalrank++;
3091 }
3092 }
3093 }
3094 ranks_after_channel1 = totalrank;
3095
3096 for (reg_178 = reg178_center - 12;
3097 reg_178 <= reg178_center + 12; reg_178 += 12) {
3098 totalrank = ranks_after_channel1;
3099 set_178(reg_178);
3100 for (slot = 0; slot < NUM_SLOTS; slot++)
3101 for (rank = 0; rank < NUM_RANKS; rank++)
3102 if (info->
3103 populated_ranks[0][slot][rank]) {
3104 train_ram_at_178(info, 0, slot,
3105 rank,
3106 totalrank,
3107 reg_178, 0,
3108 niter,
3109 timings);
3110 totalrank++;
3111 }
3112
3113 }
3114 } else {
3115 for (reg_178 = reg178_center - 12;
3116 reg_178 <= reg178_center + 12; reg_178 += 12) {
3117 totalrank = 0;
3118 set_178(reg_178);
3119 FOR_POPULATED_RANKS_BACKWARDS {
3120 train_ram_at_178(info, channel, slot, rank,
3121 totalrank, reg_178, 0, niter,
3122 timings);
3123 totalrank++;
3124 }
3125 }
3126 }
3127
3128 set_178(reg178_center);
3129 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3130 u16 tm0;
3131
3132 tm0 =
3133 choose_training(info, channel, slot, rank, lane, timings,
3134 reg178_center);
3135 write_500(info, channel, tm0,
3136 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3137 write_500(info, channel,
3138 tm0 +
3139 info->training.
3140 lane_timings[1][channel][slot][rank][lane] -
3141 info->training.
3142 lane_timings[0][channel][slot][rank][lane],
3143 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3144 }
3145
3146 totalrank = 0;
3147 FOR_POPULATED_RANKS_BACKWARDS {
3148 try_timing_offsets(info, channel, slot, rank, totalrank);
3149 totalrank++;
3150 }
Felix Held04be2dd2018-07-29 04:53:22 +02003151 MCHBAR8(0x243) = saved_243[0];
3152 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003153 write_1d0(0, 0x142, 3, 1);
3154 info->training.reg178_center = reg178_center;
3155}
3156
3157static void ram_training(struct raminfo *info)
3158{
3159 u16 saved_fc4;
3160
Felix Held04be2dd2018-07-29 04:53:22 +02003161 saved_fc4 = MCHBAR16(0xfc4);
3162 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003163
3164 if (info->revision >= 8)
3165 read_4090(info);
3166
3167 if (!try_cached_training(info))
3168 do_ram_training(info);
3169 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3170 && info->clock_speed_index < 2)
3171 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003172 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003173}
3174
Martin Roth468d02c2019-10-23 21:44:42 -06003175static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003176{
Martin Roth468d02c2019-10-23 21:44:42 -06003177 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003178 if (a > b) {
3179 t = a;
3180 a = b;
3181 b = t;
3182 }
3183 /* invariant a < b. */
3184 while (a) {
3185 t = b % a;
3186 b = a;
3187 a = t;
3188 }
3189 return b;
3190}
3191
3192static inline int div_roundup(int a, int b)
3193{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003194 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195}
3196
Martin Roth468d02c2019-10-23 21:44:42 -06003197static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003198{
3199 return (a * b) / gcd(a, b);
3200}
3201
3202struct stru1 {
3203 u8 freqs_reversed;
3204 u8 freq_diff_reduced;
3205 u8 freq_min_reduced;
3206 u8 divisor_f4_to_fmax;
3207 u8 divisor_f3_to_fmax;
3208 u8 freq4_to_max_remainder;
3209 u8 freq3_to_2_remainder;
3210 u8 freq3_to_2_remaindera;
3211 u8 freq4_to_2_remainder;
3212 int divisor_f3_to_f1, divisor_f4_to_f2;
3213 int common_time_unit_ps;
3214 int freq_max_reduced;
3215};
3216
3217static void
3218compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3219 int num_cycles_2, int num_cycles_1, int round_it,
3220 int add_freqs, struct stru1 *result)
3221{
3222 int g;
3223 int common_time_unit_ps;
3224 int freq1_reduced, freq2_reduced;
3225 int freq_min_reduced;
3226 int freq_max_reduced;
3227 int freq3, freq4;
3228
3229 g = gcd(freq1, freq2);
3230 freq1_reduced = freq1 / g;
3231 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003232 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3233 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003234
3235 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3236 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3237 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3238 if (add_freqs) {
3239 freq3 += freq2_reduced;
3240 freq4 += freq1_reduced;
3241 }
3242
3243 if (round_it) {
3244 result->freq3_to_2_remainder = 0;
3245 result->freq3_to_2_remaindera = 0;
3246 result->freq4_to_max_remainder = 0;
3247 result->divisor_f4_to_f2 = 0;
3248 result->divisor_f3_to_f1 = 0;
3249 } else {
3250 if (freq2_reduced < freq1_reduced) {
3251 result->freq3_to_2_remainder =
3252 result->freq3_to_2_remaindera =
3253 freq3 % freq1_reduced - freq1_reduced + 1;
3254 result->freq4_to_max_remainder =
3255 -(freq4 % freq1_reduced);
3256 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3257 result->divisor_f4_to_f2 =
3258 (freq4 -
3259 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3260 result->freq4_to_2_remainder =
3261 -(char)((freq1_reduced - freq2_reduced) +
3262 ((u8) freq4 -
3263 (freq1_reduced -
3264 freq2_reduced)) % (u8) freq2_reduced);
3265 } else {
3266 if (freq2_reduced > freq1_reduced) {
3267 result->freq4_to_max_remainder =
3268 (freq4 % freq2_reduced) - freq2_reduced + 1;
3269 result->freq4_to_2_remainder =
3270 freq4 % freq_max_reduced -
3271 freq_max_reduced + 1;
3272 } else {
3273 result->freq4_to_max_remainder =
3274 -(freq4 % freq2_reduced);
3275 result->freq4_to_2_remainder =
3276 -(char)(freq4 % freq_max_reduced);
3277 }
3278 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3279 result->divisor_f3_to_f1 =
3280 (freq3 -
3281 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3282 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3283 result->freq3_to_2_remaindera =
3284 -(char)((freq_max_reduced - freq_min_reduced) +
3285 (freq3 -
3286 (freq_max_reduced -
3287 freq_min_reduced)) % freq1_reduced);
3288 }
3289 }
3290 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3291 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3292 if (round_it) {
3293 if (freq2_reduced > freq1_reduced) {
3294 if (freq3 % freq_max_reduced)
3295 result->divisor_f3_to_fmax++;
3296 }
3297 if (freq2_reduced < freq1_reduced) {
3298 if (freq4 % freq_max_reduced)
3299 result->divisor_f4_to_fmax++;
3300 }
3301 }
3302 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3303 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3304 result->freq_min_reduced = freq_min_reduced;
3305 result->common_time_unit_ps = common_time_unit_ps;
3306 result->freq_max_reduced = freq_max_reduced;
3307}
3308
3309static void
3310set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3311 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3312 int num_cycles_4, int reverse)
3313{
3314 struct stru1 vv;
3315 char multiplier;
3316
3317 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3318 0, 1, &vv);
3319
3320 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003321 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003322 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3323 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3324 div_roundup(num_cycles_1,
3325 vv.common_time_unit_ps) +
3326 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3327 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3328
3329 u32 y =
3330 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3331 vv.freq_max_reduced * multiplier)
3332 | (vv.
3333 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3334 multiplier) << 16) | ((u8) (vv.
3335 freq_min_reduced
3336 *
3337 multiplier)
3338 << 24);
3339 u32 x =
3340 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3341 divisor_f3_to_f1
3342 << 16)
3343 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3344 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003345 MCHBAR32(reg) = y;
3346 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003347 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003348 MCHBAR32(reg + 4) = y;
3349 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003350 }
3351}
3352
3353static void
3354set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3355 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3356 int num_cycles_4)
3357{
3358 struct stru1 ratios1;
3359 struct stru1 ratios2;
3360
3361 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3362 0, 1, &ratios2);
3363 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3364 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003365 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003366 ratios1.freq4_to_max_remainder | (ratios2.
3367 freq4_to_max_remainder
3368 << 8)
3369 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3370 divisor_f4_to_fmax
3371 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003372 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3373 (ratios2.freq4_to_max_remainder << 8) |
3374 (ratios1.divisor_f4_to_fmax << 16) |
3375 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003376}
3377
3378static void
3379set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3380 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3381{
3382 struct stru1 ratios;
3383
3384 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3385 round_it, add_freqs, &ratios);
3386 switch (mode) {
3387 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003388 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3389 (ratios.freqs_reversed << 8);
3390 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3391 (ratios.freq4_to_max_remainder << 8) |
3392 (ratios.divisor_f3_to_fmax << 16) |
3393 (ratios.divisor_f4_to_fmax << 20) |
3394 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003395 break;
3396
3397 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003398 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3399 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003400 break;
3401
3402 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003403 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3404 (ratios.freq4_to_max_remainder << 8) |
3405 (ratios.divisor_f3_to_fmax << 16) |
3406 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003407 break;
3408
3409 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003410 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3411 (ratios.divisor_f4_to_fmax << 8) |
3412 (ratios.freqs_reversed << 12) |
3413 (ratios.freq_min_reduced << 16) |
3414 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003415 break;
3416 }
3417}
3418
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003419static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003420{
3421 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3422 0, 1);
3423 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3424 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3425 1);
3426 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3427 frequency_11(info), 1231, 1524, 0, 1);
3428 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3429 frequency_11(info) / 2, 1278, 2008, 0, 1);
3430 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3431 1167, 1539, 0, 1);
3432 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3433 frequency_11(info) / 2, 1403, 1318, 0, 1);
3434 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3435 1);
3436 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3437 1);
3438 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3439 1, 1);
3440 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3441 1);
3442 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3443 frequency_11(info) / 2, 4000, 0, 0, 0);
3444 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3445 frequency_11(info) / 2, 4000, 4000, 0, 0);
3446
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003447 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003448 printk(RAM_SPEW, "[6dc] <= %x\n",
3449 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003450 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003451 } else
3452 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3453 info->delay46_ps[0], 0,
3454 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003455 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3456 frequency_11(info), 2500, 0, 0, 0);
3457 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3458 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003459 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003460 printk(RAM_SPEW, "[6e8] <= %x\n",
3461 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003462 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003463 } else
3464 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3465 info->delay46_ps[1], 0,
3466 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003467 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3468 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3469 470, 0);
3470 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3471 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3472 454, 459, 0);
3473 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3474 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3475 2588, 0);
3476 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3477 2405, 0);
3478 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3479 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3480 480, 0);
3481 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003482 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3483 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003484}
3485
3486static u16 get_max_timing(struct raminfo *info, int channel)
3487{
3488 int slot, rank, lane;
3489 u16 ret = 0;
3490
Felix Held04be2dd2018-07-29 04:53:22 +02003491 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003492 return 384;
3493
3494 if (info->revision < 8)
3495 return 256;
3496
3497 for (slot = 0; slot < NUM_SLOTS; slot++)
3498 for (rank = 0; rank < NUM_RANKS; rank++)
3499 if (info->populated_ranks[channel][slot][rank])
3500 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003501 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003502 get_timing_register_addr
3503 (lane, 0, slot,
3504 rank), 9));
3505 return ret;
3506}
3507
3508static void set_274265(struct raminfo *info)
3509{
3510 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3511 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3512 int delay_e_over_cycle_ps;
3513 int cycletime_ps;
3514 int channel;
3515
3516 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003517 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003518 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3519 cycletime_ps =
3520 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3521 delay_d_ps =
3522 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3523 - info->some_delay_3_ps_rounded + 200;
3524 if (!
3525 ((info->silicon_revision == 0
3526 || info->silicon_revision == 1)
3527 && (info->revision >= 8)))
3528 delay_d_ps += halfcycle_ps(info) * 2;
3529 delay_d_ps +=
3530 halfcycle_ps(info) * (!info->revision_flag_1 +
3531 info->some_delay_2_halfcycles_ceil +
3532 2 * info->some_delay_1_cycle_floor +
3533 info->clock_speed_index +
3534 2 * info->cas_latency - 7 + 11);
3535 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3536
Felix Held04be2dd2018-07-29 04:53:22 +02003537 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3538 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3539 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003540 delay_d_ps += 650;
3541 delay_c_ps = delay_d_ps + 1800;
3542 if (delay_c_ps <= delay_a_ps)
3543 delay_e_ps = 0;
3544 else
3545 delay_e_ps =
3546 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3547 cycletime_ps);
3548
3549 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3550 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3551 delay_f_cycles =
3552 div_roundup(2500 - delay_e_over_cycle_ps,
3553 2 * halfcycle_ps(info));
3554 if (delay_f_cycles > delay_e_cycles) {
3555 info->delay46_ps[channel] = delay_e_ps;
3556 delay_e_cycles = 0;
3557 } else {
3558 info->delay46_ps[channel] =
3559 delay_e_over_cycle_ps +
3560 2 * halfcycle_ps(info) * delay_f_cycles;
3561 delay_e_cycles -= delay_f_cycles;
3562 }
3563
3564 if (info->delay46_ps[channel] < 2500) {
3565 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003566 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003567 }
3568 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3569 if (delay_b_ps <= delay_a_ps)
3570 delay_b_ps = 0;
3571 else
3572 delay_b_ps -= delay_a_ps;
3573 info->delay54_ps[channel] =
3574 cycletime_ps * div_roundup(delay_b_ps,
3575 cycletime_ps) -
3576 2 * halfcycle_ps(info) * delay_e_cycles;
3577 if (info->delay54_ps[channel] < 2500)
3578 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003579 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003580 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3581 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003582 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003583 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003584 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003585 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3586 4 * halfcycle_ps(info)) - 6;
3587 MCHBAR32((channel << 10) + 0x274) =
3588 info->training.reg274265[channel][1] |
3589 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003590 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003591 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3592 4 * halfcycle_ps(info)) + 1;
3593 MCHBAR16((channel << 10) + 0x265) =
3594 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003596 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003597 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598 else
Felix Held04be2dd2018-07-29 04:53:22 +02003599 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003600}
3601
3602static void restore_274265(struct raminfo *info)
3603{
3604 int channel;
3605
3606 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003607 MCHBAR32((channel << 10) + 0x274) =
3608 (info->cached_training->reg274265[channel][0] << 16) |
3609 info->cached_training->reg274265[channel][1];
3610 MCHBAR16((channel << 10) + 0x265) =
3611 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003613 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003614 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615 else
Felix Held04be2dd2018-07-29 04:53:22 +02003616 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617}
3618
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619static void dmi_setup(void)
3620{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003621 gav(DMIBAR8(0x254));
3622 DMIBAR8(0x254) = 0x1;
3623 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003624 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625
Angel Ponsd071c4d2020-09-14 23:51:35 +02003626 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627
3628 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3629 DEFAULT_GPIOBASE | 0x38);
3630 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3631}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003633void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003636 u16 ggc;
3637 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
Felix Held04be2dd2018-07-29 04:53:22 +02003639 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3641 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003642 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003643 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645
3646 dmi_setup();
3647
Felix Held04be2dd2018-07-29 04:53:22 +02003648 MCHBAR16(0x1170) = 0xa880;
3649 MCHBAR8(0x11c1) = 0x1;
3650 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003651 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003653 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3654 /* 0 for 32MB */
3655 gfxsize = 0;
3656 }
3657
3658 ggc = 0xb00 | ((gfxsize + 5) << 4);
3659
Angel Pons16fe1e02020-07-22 16:12:33 +02003660 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661
3662 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003663 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
3665 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003666 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003667 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003668 MCHBAR16_OR(0x2c30, 0x200);
3669 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003670 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003671 pci_read_config8(GMA, MSAC); // = 0x2
3672 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003673 RCBA8(0x2318);
3674 RCBA8(0x2318) = 0x47;
3675 RCBA8(0x2320);
3676 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 }
3678
Felix Heldf83d80b2018-07-29 05:30:30 +02003679 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680
Angel Pons16fe1e02020-07-22 16:12:33 +02003681 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003682 gav(RCBA32(0x3428));
3683 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003684}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003686void raminit(const int s3resume, const u8 *spd_addrmap)
3687{
Martin Roth468d02c2019-10-23 21:44:42 -06003688 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003689 int i;
3690 struct raminfo info;
3691 u8 x2ca8;
3692 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003693 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003694
Felix Held04be2dd2018-07-29 04:53:22 +02003695 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003696
3697 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3698
Angel Pons16fe1e02020-07-22 16:12:33 +02003699 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700
3701 memset(&info, 0x5a, sizeof(info));
3702
3703 info.last_500_command[0] = 0;
3704 info.last_500_command[1] = 0;
3705
3706 info.fsb_frequency = 135 * 2;
3707 info.board_lane_delay[0] = 0x14;
3708 info.board_lane_delay[1] = 0x07;
3709 info.board_lane_delay[2] = 0x07;
3710 info.board_lane_delay[3] = 0x08;
3711 info.board_lane_delay[4] = 0x56;
3712 info.board_lane_delay[5] = 0x04;
3713 info.board_lane_delay[6] = 0x04;
3714 info.board_lane_delay[7] = 0x05;
3715 info.board_lane_delay[8] = 0x10;
3716
3717 info.training.reg_178 = 0;
3718 info.training.reg_10b = 0;
3719
Angel Ponsa3868292021-01-15 22:10:13 +01003720 /* Wait for some bit, maybe TXT clear. */
3721 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3722 ;
3723
3724 /* Wait for ME to be ready */
3725 intel_early_me_init();
3726 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727
3728 /* before SPD */
3729 timestamp_add_now(101);
3730
Felix Held29a9c072018-07-29 01:34:45 +02003731 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003732 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3733
3734 info.use_ecc = 1;
3735 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003736 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003737 int v;
3738 int try;
3739 int addr;
3740 const u8 useful_addresses[] = {
3741 DEVICE_TYPE,
3742 MODULE_TYPE,
3743 DENSITY,
3744 RANKS_AND_DQ,
3745 MEMORY_BUS_WIDTH,
3746 TIMEBASE_DIVIDEND,
3747 TIMEBASE_DIVISOR,
3748 CYCLETIME,
3749 CAS_LATENCIES_LSB,
3750 CAS_LATENCIES_MSB,
3751 CAS_LATENCY_TIME,
3752 0x11, 0x12, 0x13, 0x14, 0x15,
3753 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3754 0x1c, 0x1d,
3755 THERMAL_AND_REFRESH,
3756 0x20,
3757 REFERENCE_RAW_CARD_USED,
3758 RANK1_ADDRESS_MAPPING,
3759 0x75, 0x76, 0x77, 0x78,
3760 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3761 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3762 0x85, 0x86, 0x87, 0x88,
3763 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3764 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3765 0x95
3766 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003767 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003768 continue;
3769 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003770 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771 DEVICE_TYPE);
3772 if (v >= 0)
3773 break;
3774 }
3775 if (v < 0)
3776 continue;
3777 for (addr = 0;
3778 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003779 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003780 gav(info.
3781 spd[channel][0][useful_addresses
3782 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003783 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003784 useful_addresses
3785 [addr]));
3786 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3787 die("Only DDR3 is supported");
3788
3789 v = info.spd[channel][0][RANKS_AND_DQ];
3790 info.populated_ranks[channel][0][0] = 1;
3791 info.populated_ranks[channel][0][1] =
3792 ((v >> 3) & 7);
3793 if (((v >> 3) & 7) > 1)
3794 die("At most 2 ranks are supported");
3795 if ((v & 7) == 0 || (v & 7) > 2)
3796 die("Only x8 and x16 modules are supported");
3797 if ((info.
3798 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3799 && (info.
3800 spd[channel][slot][MODULE_TYPE] & 0xF)
3801 != 3)
3802 die("Registered memory is not supported");
3803 info.is_x16_module[channel][0] = (v & 7) - 1;
3804 info.density[channel][slot] =
3805 info.spd[channel][slot][DENSITY] & 0xF;
3806 if (!
3807 (info.
3808 spd[channel][slot][MEMORY_BUS_WIDTH] &
3809 0x18))
3810 info.use_ecc = 0;
3811 }
3812
3813 gav(0x55);
3814
3815 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3816 int v = 0;
3817 for (slot = 0; slot < NUM_SLOTS; slot++)
3818 for (rank = 0; rank < NUM_RANKS; rank++)
3819 v |= info.
3820 populated_ranks[channel][slot][rank]
3821 << (2 * slot + rank);
3822 info.populated_ranks_mask[channel] = v;
3823 }
3824
3825 gav(0x55);
3826
Angel Pons16fe1e02020-07-22 16:12:33 +02003827 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003828 }
3829
3830 /* after SPD */
3831 timestamp_add_now(102);
3832
Felix Held04be2dd2018-07-29 04:53:22 +02003833 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003834
3835 collect_system_info(&info);
3836 calculate_timings(&info);
3837
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003838 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003839 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840 if (x2ca8 == 0 && (reg8 & 0x80)) {
3841 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3842 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3843 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3844 */
3845
3846 /* Clear bit7. */
3847
3848 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3849 (reg8 & ~(1 << 7)));
3850
3851 printk(BIOS_INFO,
3852 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003853 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003854 }
3855 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003856
3857 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003858 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3859 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003860
3861 compute_derived_timings(&info);
3862
3863 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003864 gav(MCHBAR8(0x164));
3865 MCHBAR8(0x164) = 0x26;
3866 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867 }
3868
Felix Held04be2dd2018-07-29 04:53:22 +02003869 MCHBAR32_OR(0x18b4, 0x210000);
3870 MCHBAR32_OR(0x1890, 0x2000000);
3871 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872
Angel Ponsa457e352020-07-22 18:17:33 +02003873 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3874 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875
Felix Held04be2dd2018-07-29 04:53:22 +02003876 gav(MCHBAR16(0x2c10));
3877 MCHBAR16(0x2c10) = 0x412;
3878 gav(MCHBAR16(0x2c10));
3879 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880
Felix Held04be2dd2018-07-29 04:53:22 +02003881 gav(MCHBAR8(0x2ca8)); // !!!!
3882 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003883
Angel Ponsa457e352020-07-22 18:17:33 +02003884 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3885 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003886 gav(MCHBAR32(0x1c04)); // !!!!
3887 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003888
3889 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003890 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003891 }
3892
Felix Held04be2dd2018-07-29 04:53:22 +02003893 MCHBAR32(0x18d8) = 0x120000;
3894 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003895 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3896 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR32(0x18d8) = 0x40000;
3898 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003899 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3900 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003901 MCHBAR32(0x18d8) = 0x180000;
3902 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003903 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3904 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003905 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906
Felix Held04be2dd2018-07-29 04:53:22 +02003907 gav(MCHBAR32(0x18dc)); // !!!!
3908 MCHBAR32(0x18dc) = 0x3;
3909 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910
3911 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003912 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913 }
3914
Felix Held04be2dd2018-07-29 04:53:22 +02003915 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003916 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003917 MCHBAR32(0x1a10) = 0x4200010e;
3918 MCHBAR32_OR(0x18b8, 0x200);
3919 gav(MCHBAR32(0x1918)); // !!!!
3920 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921
Felix Held04be2dd2018-07-29 04:53:22 +02003922 gav(MCHBAR32(0x18b8)); // !!!!
3923 MCHBAR32(0x18b8) = 0xe00;
3924 gav(MCHBAR32(0x182c)); // !!!!
3925 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003926 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3927 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003928 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3929 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930
Felix Held04be2dd2018-07-29 04:53:22 +02003931 MCHBAR32_AND(0x18b4, 0xffff7fff);
3932 gav(MCHBAR32(0x1a68)); // !!!!
3933 MCHBAR32(0x1a68) = 0x343800;
3934 gav(MCHBAR32(0x1e68)); // !!!!
3935 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003936
3937 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003938 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003939 }
3940
Angel Pons08143572020-07-22 17:47:06 +02003941 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3942 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3943 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3944 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3945 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003946 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3947 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003948 gav(MCHBAR32(0x1af0)); // !!!!
3949 gav(MCHBAR32(0x1af0)); // !!!!
3950 MCHBAR32(0x1af0) = 0x1f020003;
3951 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003953 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003954 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003955 }
3956
Felix Held04be2dd2018-07-29 04:53:22 +02003957 gav(MCHBAR32(0x1890)); // !!!!
3958 MCHBAR32(0x1890) = 0x80102;
3959 gav(MCHBAR32(0x18b4)); // !!!!
3960 MCHBAR32(0x18b4) = 0x216000;
3961 MCHBAR32(0x18a4) = 0x22222222;
3962 MCHBAR32(0x18a8) = 0x22222222;
3963 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003964
3965 udelay(1000);
3966
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003967 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003968
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003969 if (x2ca8 == 0) {
3970 int j;
3971 if (s3resume && info.cached_training) {
3972 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003973 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003974 info.cached_training->reg2ca9_bit0);
3975 for (i = 0; i < 2; i++)
3976 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003977 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003978 i, j, info.cached_training->reg274265[i][j]);
3979 } else {
3980 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003981 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003982 info.training.reg2ca9_bit0);
3983 for (i = 0; i < 2; i++)
3984 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003985 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003986 i, j, info.training.reg274265[i][j]);
3987 }
3988
3989 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003990
3991 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02003992 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003993 }
3994
3995 udelay(1000);
3996
3997 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003998 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02003999 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004000 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4001 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4002 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004003
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004004 MCHBAR8(0x1150);
4005 MCHBAR8(0x1151);
4006 MCHBAR8(0x1022);
4007 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004008 MCHBAR32(0x1300) = 0x60606060;
4009 MCHBAR32(0x1304) = 0x60606060;
4010 MCHBAR32(0x1308) = 0x78797a7b;
4011 MCHBAR32(0x130c) = 0x7c7d7e7f;
4012 MCHBAR32(0x1310) = 0x60606060;
4013 MCHBAR32(0x1314) = 0x60606060;
4014 MCHBAR32(0x1318) = 0x60606060;
4015 MCHBAR32(0x131c) = 0x60606060;
4016 MCHBAR32(0x1320) = 0x50515253;
4017 MCHBAR32(0x1324) = 0x54555657;
4018 MCHBAR32(0x1328) = 0x58595a5b;
4019 MCHBAR32(0x132c) = 0x5c5d5e5f;
4020 MCHBAR32(0x1330) = 0x40414243;
4021 MCHBAR32(0x1334) = 0x44454647;
4022 MCHBAR32(0x1338) = 0x48494a4b;
4023 MCHBAR32(0x133c) = 0x4c4d4e4f;
4024 MCHBAR32(0x1340) = 0x30313233;
4025 MCHBAR32(0x1344) = 0x34353637;
4026 MCHBAR32(0x1348) = 0x38393a3b;
4027 MCHBAR32(0x134c) = 0x3c3d3e3f;
4028 MCHBAR32(0x1350) = 0x20212223;
4029 MCHBAR32(0x1354) = 0x24252627;
4030 MCHBAR32(0x1358) = 0x28292a2b;
4031 MCHBAR32(0x135c) = 0x2c2d2e2f;
4032 MCHBAR32(0x1360) = 0x10111213;
4033 MCHBAR32(0x1364) = 0x14151617;
4034 MCHBAR32(0x1368) = 0x18191a1b;
4035 MCHBAR32(0x136c) = 0x1c1d1e1f;
4036 MCHBAR32(0x1370) = 0x10203;
4037 MCHBAR32(0x1374) = 0x4050607;
4038 MCHBAR32(0x1378) = 0x8090a0b;
4039 MCHBAR32(0x137c) = 0xc0d0e0f;
4040 MCHBAR8(0x11cc) = 0x4e;
4041 MCHBAR32(0x1110) = 0x73970404;
4042 MCHBAR32(0x1114) = 0x72960404;
4043 MCHBAR32(0x1118) = 0x6f950404;
4044 MCHBAR32(0x111c) = 0x6d940404;
4045 MCHBAR32(0x1120) = 0x6a930404;
4046 MCHBAR32(0x1124) = 0x68a41404;
4047 MCHBAR32(0x1128) = 0x66a21404;
4048 MCHBAR32(0x112c) = 0x63a01404;
4049 MCHBAR32(0x1130) = 0x609e1404;
4050 MCHBAR32(0x1134) = 0x5f9c1404;
4051 MCHBAR32(0x1138) = 0x5c961404;
4052 MCHBAR32(0x113c) = 0x58a02404;
4053 MCHBAR32(0x1140) = 0x54942404;
4054 MCHBAR32(0x1190) = 0x900080a;
4055 MCHBAR16(0x11c0) = 0xc40b;
4056 MCHBAR16(0x11c2) = 0x303;
4057 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004058 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004059 MCHBAR32(0x11b8) = 0x70c3000;
4060 MCHBAR8(0x11ec) = 0xa;
4061 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004062 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004063 MCHBAR16(0x11ca) = 0xfa;
4064 MCHBAR32(0x11e4) = 0x4e20;
4065 MCHBAR8(0x11bc) = 0xf;
4066 MCHBAR16(0x11da) = 0x19;
4067 MCHBAR16(0x11ba) = 0x470c;
4068 MCHBAR32(0x1680) = 0xe6ffe4ff;
4069 MCHBAR32(0x1684) = 0xdeffdaff;
4070 MCHBAR32(0x1688) = 0xd4ffd0ff;
4071 MCHBAR32(0x168c) = 0xccffc6ff;
4072 MCHBAR32(0x1690) = 0xc0ffbeff;
4073 MCHBAR32(0x1694) = 0xb8ffb0ff;
4074 MCHBAR32(0x1698) = 0xa8ff0000;
4075 MCHBAR32(0x169c) = 0xc00;
4076 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004077 }
4078
Felix Held04be2dd2018-07-29 04:53:22 +02004079 MCHBAR32(0x124c) = 0x15040d00;
4080 MCHBAR32(0x1250) = 0x7f0000;
4081 MCHBAR32(0x1254) = 0x1e220004;
4082 MCHBAR32(0x1258) = 0x4000004;
4083 MCHBAR32(0x1278) = 0x0;
4084 MCHBAR32(0x125c) = 0x0;
4085 MCHBAR32(0x1260) = 0x0;
4086 MCHBAR32(0x1264) = 0x0;
4087 MCHBAR32(0x1268) = 0x0;
4088 MCHBAR32(0x126c) = 0x0;
4089 MCHBAR32(0x1270) = 0x0;
4090 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004091 }
4092
4093 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004094 MCHBAR16(0x1214) = 0x320;
4095 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004096 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4097 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004098 MCHBAR32(0x1400) = 0x13040020;
4099 MCHBAR32(0x1404) = 0xe090120;
4100 MCHBAR32(0x1408) = 0x5120220;
4101 MCHBAR32(0x140c) = 0x5120330;
4102 MCHBAR32(0x1410) = 0xe090220;
4103 MCHBAR32(0x1414) = 0x1010001;
4104 MCHBAR32(0x1418) = 0x1110000;
4105 MCHBAR32(0x141c) = 0x9020020;
4106 MCHBAR32(0x1420) = 0xd090220;
4107 MCHBAR32(0x1424) = 0x2090220;
4108 MCHBAR32(0x1428) = 0x2090330;
4109 MCHBAR32(0x142c) = 0xd090220;
4110 MCHBAR32(0x1430) = 0x1010001;
4111 MCHBAR32(0x1434) = 0x1110000;
4112 MCHBAR32(0x1438) = 0x11040020;
4113 MCHBAR32(0x143c) = 0x4030220;
4114 MCHBAR32(0x1440) = 0x1060220;
4115 MCHBAR32(0x1444) = 0x1060330;
4116 MCHBAR32(0x1448) = 0x4030220;
4117 MCHBAR32(0x144c) = 0x1010001;
4118 MCHBAR32(0x1450) = 0x1110000;
4119 MCHBAR32(0x1454) = 0x4010020;
4120 MCHBAR32(0x1458) = 0xb090220;
4121 MCHBAR32(0x145c) = 0x1090220;
4122 MCHBAR32(0x1460) = 0x1090330;
4123 MCHBAR32(0x1464) = 0xb090220;
4124 MCHBAR32(0x1468) = 0x1010001;
4125 MCHBAR32(0x146c) = 0x1110000;
4126 MCHBAR32(0x1470) = 0xf040020;
4127 MCHBAR32(0x1474) = 0xa090220;
4128 MCHBAR32(0x1478) = 0x1120220;
4129 MCHBAR32(0x147c) = 0x1120330;
4130 MCHBAR32(0x1480) = 0xa090220;
4131 MCHBAR32(0x1484) = 0x1010001;
4132 MCHBAR32(0x1488) = 0x1110000;
4133 MCHBAR32(0x148c) = 0x7020020;
4134 MCHBAR32(0x1490) = 0x1010220;
4135 MCHBAR32(0x1494) = 0x10210;
4136 MCHBAR32(0x1498) = 0x10320;
4137 MCHBAR32(0x149c) = 0x1010220;
4138 MCHBAR32(0x14a0) = 0x1010001;
4139 MCHBAR32(0x14a4) = 0x1110000;
4140 MCHBAR32(0x14a8) = 0xd040020;
4141 MCHBAR32(0x14ac) = 0x8090220;
4142 MCHBAR32(0x14b0) = 0x1111310;
4143 MCHBAR32(0x14b4) = 0x1111420;
4144 MCHBAR32(0x14b8) = 0x8090220;
4145 MCHBAR32(0x14bc) = 0x1010001;
4146 MCHBAR32(0x14c0) = 0x1110000;
4147 MCHBAR32(0x14c4) = 0x3010020;
4148 MCHBAR32(0x14c8) = 0x7090220;
4149 MCHBAR32(0x14cc) = 0x1081310;
4150 MCHBAR32(0x14d0) = 0x1081420;
4151 MCHBAR32(0x14d4) = 0x7090220;
4152 MCHBAR32(0x14d8) = 0x1010001;
4153 MCHBAR32(0x14dc) = 0x1110000;
4154 MCHBAR32(0x14e0) = 0xb040020;
4155 MCHBAR32(0x14e4) = 0x2030220;
4156 MCHBAR32(0x14e8) = 0x1051310;
4157 MCHBAR32(0x14ec) = 0x1051420;
4158 MCHBAR32(0x14f0) = 0x2030220;
4159 MCHBAR32(0x14f4) = 0x1010001;
4160 MCHBAR32(0x14f8) = 0x1110000;
4161 MCHBAR32(0x14fc) = 0x5020020;
4162 MCHBAR32(0x1500) = 0x5090220;
4163 MCHBAR32(0x1504) = 0x2071310;
4164 MCHBAR32(0x1508) = 0x2071420;
4165 MCHBAR32(0x150c) = 0x5090220;
4166 MCHBAR32(0x1510) = 0x1010001;
4167 MCHBAR32(0x1514) = 0x1110000;
4168 MCHBAR32(0x1518) = 0x7040120;
4169 MCHBAR32(0x151c) = 0x2090220;
4170 MCHBAR32(0x1520) = 0x70b1210;
4171 MCHBAR32(0x1524) = 0x70b1310;
4172 MCHBAR32(0x1528) = 0x2090220;
4173 MCHBAR32(0x152c) = 0x1010001;
4174 MCHBAR32(0x1530) = 0x1110000;
4175 MCHBAR32(0x1534) = 0x1010110;
4176 MCHBAR32(0x1538) = 0x1081310;
4177 MCHBAR32(0x153c) = 0x5041200;
4178 MCHBAR32(0x1540) = 0x5041310;
4179 MCHBAR32(0x1544) = 0x1081310;
4180 MCHBAR32(0x1548) = 0x1010001;
4181 MCHBAR32(0x154c) = 0x1110000;
4182 MCHBAR32(0x1550) = 0x1040120;
4183 MCHBAR32(0x1554) = 0x4051210;
4184 MCHBAR32(0x1558) = 0xd051200;
4185 MCHBAR32(0x155c) = 0xd051200;
4186 MCHBAR32(0x1560) = 0x4051210;
4187 MCHBAR32(0x1564) = 0x1010001;
4188 MCHBAR32(0x1568) = 0x1110000;
4189 MCHBAR16(0x1222) = 0x220a;
4190 MCHBAR16(0x123c) = 0x1fc0;
4191 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004192 }
4193
Angel Ponsc627dc92020-09-22 17:06:44 +02004194 MCHBAR32_OR(0x2c80, (1 << 24));
4195 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004196
Angel Ponsc627dc92020-09-22 17:06:44 +02004197 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004198
4199 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004200 MCHBAR8_AND(0x2ca8, ~3);
4201 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004202 /* This issues a CPU reset without resetting the platform */
4203 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004204 /* Write back the S3 state to PM1_CNT to let the reset CPU
4205 know it also needs to take the s3 path. */
4206 if (s3resume)
4207 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4208 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004209 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004210 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004211 }
Angel Ponsc627dc92020-09-22 17:06:44 +02004212 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004213
Angel Ponsc627dc92020-09-22 17:06:44 +02004214 MCHBAR32_AND(0x2c80, ~(1 << 24));
4215
Angel Pons9addda32020-07-22 18:37:32 +02004216 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02004217
4218 {
4219 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
4220 u16 x2c10 = MCHBAR16(0x2c10);
4221 u16 value = MCHBAR16(0x2c00);
4222 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
4223 value |= (1 << 7);
4224 else
4225 value &= ~(1 << 0);
4226
4227 MCHBAR16(0x2c00) = value;
4228 }
4229
4230 udelay(1000); // !!!!
4231
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004232 write_1d0(0, 0x33d, 0, 0);
4233 write_500(&info, 0, 0, 0xb61, 0, 0);
4234 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004235 MCHBAR32(0x1a30) = 0x0;
4236 MCHBAR32(0x1a34) = 0x0;
4237 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4238 (info.populated_ranks[0][0][0] * 0xa0);
4239 MCHBAR16(0x616) = 0x26a;
4240 MCHBAR32(0x134) = 0x856000;
4241 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004242 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4243 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004244 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004245 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4246 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004247 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004248 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004249 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4250 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004251 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4252 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4253 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4254 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4255 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4256 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4257 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4258 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4259 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4260 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004261 }
4262
4263 write_1d0(0x4, 0x151, 4, 1);
4264 write_1d0(0, 0x142, 3, 1);
4265 rdmsr(0x1ac); // !!!!
4266 write_500(&info, 1, 1, 0x6b3, 4, 1);
4267 write_500(&info, 1, 1, 0x6cf, 4, 1);
4268
Angel Pons244f4552021-01-15 20:41:36 +01004269 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270
4271 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4272 populated_ranks[0]
4273 [0][0]) << 0),
4274 0x1d1, 3, 1);
4275 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004276 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4277 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004278 }
4279
4280 set_334(0);
4281
4282 program_base_timings(&info);
4283
Felix Held04be2dd2018-07-29 04:53:22 +02004284 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004285
4286 write_1d0(0x2, 0x1d5, 2, 1);
4287 write_1d0(0x20, 0x166, 7, 1);
4288 write_1d0(0x0, 0xeb, 3, 1);
4289 write_1d0(0x0, 0xf3, 6, 1);
4290
4291 for (channel = 0; channel < NUM_CHANNELS; channel++)
4292 for (lane = 0; lane < 9; lane++) {
4293 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4294 u8 a;
4295 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4296 write_500(&info, channel, a, addr, 6, 1);
4297 }
4298
4299 udelay(1000);
4300
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004301 if (s3resume) {
4302 if (info.cached_training == NULL) {
4303 u32 reg32;
4304 printk(BIOS_ERR,
4305 "Couldn't find training data. Rebooting\n");
4306 reg32 = inl(DEFAULT_PMBASE + 0x04);
4307 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004308 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004309 }
4310 int tm;
4311 info.training = *info.cached_training;
4312 for (tm = 0; tm < 4; tm++)
4313 for (channel = 0; channel < NUM_CHANNELS; channel++)
4314 for (slot = 0; slot < NUM_SLOTS; slot++)
4315 for (rank = 0; rank < NUM_RANKS; rank++)
4316 for (lane = 0; lane < 9; lane++)
4317 write_500(&info,
4318 channel,
4319 info.training.
4320 lane_timings
4321 [tm][channel]
4322 [slot][rank]
4323 [lane],
4324 get_timing_register_addr
4325 (lane, tm,
4326 slot, rank),
4327 9, 0);
4328 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4329 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4330 }
4331
Felix Heldf83d80b2018-07-29 05:30:30 +02004332 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004333 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02004334 MCHBAR8_OR(0x1f0, 0x1);
4335 while (MCHBAR8(0x1f0) & 1)
4336 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004337
4338 program_board_delay(&info);
4339
Felix Held04be2dd2018-07-29 04:53:22 +02004340 MCHBAR8(0x5ff) = 0x0;
4341 MCHBAR8(0x5ff) = 0x80;
4342 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004343
Felix Held04be2dd2018-07-29 04:53:22 +02004344 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004345 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004346 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02004347
4348 rmw_1d0(0x14b, 0x47, 0x30, 7);
4349 rmw_1d0(0xd6, 0x38, 7, 6);
4350 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004351
4352 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004353 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004354
Angel Ponsc627dc92020-09-22 17:06:44 +02004355 rmw_1d0(0x116, 0xe, 0, 4);
4356 rmw_1d0(0xae, 0x3e, 0, 6);
4357 rmw_1d0(0x300, 0x3e, 0, 6);
4358 MCHBAR16_AND(0x356, 0x7fff);
4359 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02004360 MCHBAR32_AND(0x140, ~0x07000000);
4361 MCHBAR32_AND(0x138, ~0x07000000);
4362 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004363 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004364 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004365 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004366
4367 {
4368 u32 t;
4369 u8 val_a1;
4370 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4371 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4372 rmw_1d0(0x320, 0x07,
Angel Pons244f4552021-01-15 20:41:36 +01004373 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004374 rmw_1d0(0x14b, 0x78,
4375 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004376 4), 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004377 rmw_1d0(0xce, 0x38,
4378 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
Angel Pons244f4552021-01-15 20:41:36 +01004379 4), 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004380 }
4381
4382 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004383 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004384
Angel Pons244f4552021-01-15 20:41:36 +01004385 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004386 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004387 write_1d0(2, 0xae, 6, 1);
4388 write_1d0(2, 0x300, 6, 1);
4389 write_1d0(2, 0x121, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02004390 rmw_1d0(0xd6, 0x38, 4, 6);
4391 rmw_1d0(0x328, 0x38, 4, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004392
4393 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004394 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004395
Felix Held04be2dd2018-07-29 04:53:22 +02004396 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4397 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004398 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004399 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02004400
4401 {
4402 u32 reg32 = read_1d0(0xa1, 6);
4403 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4404 rmw_1d0(0x21c, 0x38, 0, 6);
4405 u8 reg8 = 0;
4406 reg8 |= (reg32 >> 4) & (1 << 0);
4407 reg8 |= (reg32 >> 2) & (1 << 1);
4408 reg8 |= (reg32 >> 0) & (1 << 2);
4409 rmw_1d0(0x14b, 0x78, reg8, 7);
4410 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004411
4412 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004413 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004414
4415 set_334(1);
4416
Felix Held04be2dd2018-07-29 04:53:22 +02004417 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004418
4419 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4420 write_500(&info, channel,
4421 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4422 1);
4423 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4424 }
Felix Held04be2dd2018-07-29 04:53:22 +02004425 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4426 MCHBAR16(0x6c0) = 0x14a0;
4427 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4428 MCHBAR16(0x232) = 0x8;
4429 /* 0x40004 or 0 depending on ? */
4430 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4431 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4432 MCHBAR32(0x128) = 0x2150d05;
4433 MCHBAR8(0x12c) = 0x1f;
4434 MCHBAR8(0x12d) = 0x56;
4435 MCHBAR8(0x12e) = 0x31;
4436 MCHBAR8(0x12f) = 0x0;
4437 MCHBAR8(0x271) = 0x2;
4438 MCHBAR8(0x671) = 0x2;
4439 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004440 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004441 MCHBAR32(0x294 + (channel << 10)) =
4442 (info.populated_ranks_mask[channel] & 3) << 16;
4443 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4444 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004445 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004446 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4447 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004448
4449 if (!s3resume)
4450 jedec_init(&info);
4451
4452 int totalrank = 0;
4453 for (channel = 0; channel < NUM_CHANNELS; channel++)
4454 for (slot = 0; slot < NUM_SLOTS; slot++)
4455 for (rank = 0; rank < NUM_RANKS; rank++)
4456 if (info.populated_ranks[channel][slot][rank]) {
4457 jedec_read(&info, channel, slot, rank,
4458 totalrank, 0xa, 0x400);
4459 totalrank++;
4460 }
4461
Felix Held04be2dd2018-07-29 04:53:22 +02004462 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004463
Angel Ponsc627dc92020-09-22 17:06:44 +02004464 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
4465 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004466
4467 if (!s3resume) {
4468 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004469 MCHBAR32(0x294 + (channel << 10)) =
4470 (info.populated_ranks_mask[channel] & 3) << 16;
4471 MCHBAR16(0x298 + (channel << 10)) =
4472 info.populated_ranks[channel][0][0] |
4473 (info.populated_ranks[channel][0][1] << 5);
4474 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004476 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004477
4478 {
4479 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004480 a = MCHBAR8(0x243);
4481 b = MCHBAR8(0x643);
4482 MCHBAR8(0x243) = a | 2;
4483 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484 }
4485
4486 write_1d0(7, 0x19b, 3, 1);
4487 write_1d0(7, 0x1c0, 3, 1);
4488 write_1d0(4, 0x1c6, 4, 1);
4489 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02004490 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02004491 MCHBAR32(0x584) = 0xfffff;
4492 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493
4494 for (channel = 0; channel < NUM_CHANNELS; channel++)
4495 for (slot = 0; slot < NUM_SLOTS; slot++)
4496 for (rank = 0; rank < NUM_RANKS; rank++)
4497 if (info.
4498 populated_ranks[channel][slot]
4499 [rank])
4500 config_rank(&info, s3resume,
4501 channel, slot,
4502 rank);
4503
Felix Held04be2dd2018-07-29 04:53:22 +02004504 MCHBAR8(0x243) = 0x1;
4505 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506 }
4507
4508 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004509 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510 write_26c(0, 0x820);
4511 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004512 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513 /* end */
4514
4515 if (s3resume) {
4516 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004517 MCHBAR32(0x294 + (channel << 10)) =
4518 (info.populated_ranks_mask[channel] & 3) << 16;
4519 MCHBAR16(0x298 + (channel << 10)) =
4520 info.populated_ranks[channel][0][0] |
4521 (info.populated_ranks[channel][0][1] << 5);
4522 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004524 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004525 }
4526
Felix Held04be2dd2018-07-29 04:53:22 +02004527 MCHBAR32_AND(0xfa4, ~0x01000002);
4528 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004530 /* Before training. */
4531 timestamp_add_now(103);
4532
4533 if (!s3resume)
4534 ram_training(&info);
4535
4536 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004537 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004538
4539 dump_timings(&info);
4540
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 program_modules_memory_map(&info, 0);
4542 program_total_memory_map(&info);
4543
4544 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004545 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004546 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004548 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004549 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550 else
Felix Held04be2dd2018-07-29 04:53:22 +02004551 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004552
Felix Held04be2dd2018-07-29 04:53:22 +02004553 MCHBAR32_AND(0xfac, ~0x80000000);
4554 MCHBAR32(0xfb4) = 0x4800;
4555 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4556 MCHBAR32(0xe94) = 0x7ffff;
4557 MCHBAR32(0xfc0) = 0x80002040;
4558 MCHBAR32(0xfc4) = 0x701246;
4559 MCHBAR8_AND(0xfc8, ~0x70);
4560 MCHBAR32_OR(0xe5c, 0x1000000);
4561 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4562 MCHBAR32(0x50) = 0x700b0;
4563 MCHBAR32(0x3c) = 0x10;
4564 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4565 MCHBAR8_OR(0xff4, 0x2);
4566 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004567
Felix Held04be2dd2018-07-29 04:53:22 +02004568 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4569 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4570 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004572 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4573 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4574 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 {
4577 u32 eax;
4578
4579 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4581 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4582 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583 }
4584
4585 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004586 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 else
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004591
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593
Felix Held04be2dd2018-07-29 04:53:22 +02004594 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004595 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597 else
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599 }
4600
Felix Held04be2dd2018-07-29 04:53:22 +02004601 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004602
4603 {
4604 u8 al;
4605 al = 0xd;
4606 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4607 al += 2;
4608 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004609 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004610 }
4611
4612 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004613 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4614 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4615 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4616 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004617 }
4618 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004619 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004620 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004621 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004622 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004623 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004624 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004625 MCHBAR8_OR(0x1210, 2);
4626 MCHBAR32(0x1200) = 0x8800440;
4627 MCHBAR32(0x1204) = 0x53ff0453;
4628 MCHBAR32(0x1208) = 0x19002043;
4629 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630
4631 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR16(0x1214) = 0x220;
4633 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634 }
4635
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR8_OR(0x1214, 0x4);
4637 MCHBAR8(0x120c) = 0x1;
4638 MCHBAR8(0x1218) = 0x3;
4639 MCHBAR8(0x121a) = 0x3;
4640 MCHBAR8(0x121c) = 0x3;
4641 MCHBAR16(0xc14) = 0x0;
4642 MCHBAR16(0xc20) = 0x0;
4643 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644
4645 /* revision dependent here. */
4646
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648
4649 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004650 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR16_OR(0x1230, 0x8000);
4653 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
4655 u8 bl, ebpb;
4656 u16 reg_1020;
4657
Felix Held04be2dd2018-07-29 04:53:22 +02004658 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4659 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660
Felix Held04be2dd2018-07-29 04:53:22 +02004661 MCHBAR32(0x1000) = 0x100;
4662 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
4664 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004665 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004666 bl = reg_1020 >> 8;
4667 ebpb = reg_1020 & 0xff;
4668 } else {
4669 ebpb = 0;
4670 bl = 8;
4671 }
4672
4673 rdmsr(0x1a2);
4674
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676
Felix Held04be2dd2018-07-29 04:53:22 +02004677 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678
Felix Held04be2dd2018-07-29 04:53:22 +02004679 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004682 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004683 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4684 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004685 }
4686
4687 setup_heci_uma(&info);
4688
4689 if (info.uma_enabled) {
4690 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR32_OR(0x11b0, 0x4000);
4692 MCHBAR32_OR(0x11b4, 0x4000);
4693 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
Felix Held04be2dd2018-07-29 04:53:22 +02004695 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4696 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4697 MCHBAR16_OR(0x1170, 0x1000);
4698
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004700
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004702 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004703 ;
4704 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705 }
4706
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004707 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4708 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004710 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712 udelay(1000);
4713 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004714 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4715
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004716 if (!s3resume)
4717 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004718 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004719 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004720 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004721
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004722 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004723 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004724 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725}