blob: b9835beb160a984271ed6a97377eb476b21fcc20 [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
Angel Pons26681912021-01-15 21:36:28 +01003686static u8 get_bits_420(const u32 reg32)
3687{
3688 u8 val = 0;
3689 val |= (reg32 >> 4) & (1 << 0);
3690 val |= (reg32 >> 2) & (1 << 1);
3691 val |= (reg32 >> 0) & (1 << 2);
3692 return val;
3693}
3694
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003695void raminit(const int s3resume, const u8 *spd_addrmap)
3696{
Martin Roth468d02c2019-10-23 21:44:42 -06003697 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003698 int i;
3699 struct raminfo info;
3700 u8 x2ca8;
3701 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003702 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003703
Felix Held04be2dd2018-07-29 04:53:22 +02003704 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003705
3706 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3707
Angel Pons16fe1e02020-07-22 16:12:33 +02003708 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003709
3710 memset(&info, 0x5a, sizeof(info));
3711
3712 info.last_500_command[0] = 0;
3713 info.last_500_command[1] = 0;
3714
3715 info.fsb_frequency = 135 * 2;
3716 info.board_lane_delay[0] = 0x14;
3717 info.board_lane_delay[1] = 0x07;
3718 info.board_lane_delay[2] = 0x07;
3719 info.board_lane_delay[3] = 0x08;
3720 info.board_lane_delay[4] = 0x56;
3721 info.board_lane_delay[5] = 0x04;
3722 info.board_lane_delay[6] = 0x04;
3723 info.board_lane_delay[7] = 0x05;
3724 info.board_lane_delay[8] = 0x10;
3725
3726 info.training.reg_178 = 0;
3727 info.training.reg_10b = 0;
3728
Angel Ponsa3868292021-01-15 22:10:13 +01003729 /* Wait for some bit, maybe TXT clear. */
3730 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3731 ;
3732
3733 /* Wait for ME to be ready */
3734 intel_early_me_init();
3735 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003736
3737 /* before SPD */
3738 timestamp_add_now(101);
3739
Felix Held29a9c072018-07-29 01:34:45 +02003740 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003741 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3742
3743 info.use_ecc = 1;
3744 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003745 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003746 int v;
3747 int try;
3748 int addr;
3749 const u8 useful_addresses[] = {
3750 DEVICE_TYPE,
3751 MODULE_TYPE,
3752 DENSITY,
3753 RANKS_AND_DQ,
3754 MEMORY_BUS_WIDTH,
3755 TIMEBASE_DIVIDEND,
3756 TIMEBASE_DIVISOR,
3757 CYCLETIME,
3758 CAS_LATENCIES_LSB,
3759 CAS_LATENCIES_MSB,
3760 CAS_LATENCY_TIME,
3761 0x11, 0x12, 0x13, 0x14, 0x15,
3762 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3763 0x1c, 0x1d,
3764 THERMAL_AND_REFRESH,
3765 0x20,
3766 REFERENCE_RAW_CARD_USED,
3767 RANK1_ADDRESS_MAPPING,
3768 0x75, 0x76, 0x77, 0x78,
3769 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3770 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3771 0x85, 0x86, 0x87, 0x88,
3772 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3773 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3774 0x95
3775 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003776 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003777 continue;
3778 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003779 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003780 DEVICE_TYPE);
3781 if (v >= 0)
3782 break;
3783 }
3784 if (v < 0)
3785 continue;
3786 for (addr = 0;
3787 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003788 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003789 gav(info.
3790 spd[channel][0][useful_addresses
3791 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003792 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003793 useful_addresses
3794 [addr]));
3795 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3796 die("Only DDR3 is supported");
3797
3798 v = info.spd[channel][0][RANKS_AND_DQ];
3799 info.populated_ranks[channel][0][0] = 1;
3800 info.populated_ranks[channel][0][1] =
3801 ((v >> 3) & 7);
3802 if (((v >> 3) & 7) > 1)
3803 die("At most 2 ranks are supported");
3804 if ((v & 7) == 0 || (v & 7) > 2)
3805 die("Only x8 and x16 modules are supported");
3806 if ((info.
3807 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3808 && (info.
3809 spd[channel][slot][MODULE_TYPE] & 0xF)
3810 != 3)
3811 die("Registered memory is not supported");
3812 info.is_x16_module[channel][0] = (v & 7) - 1;
3813 info.density[channel][slot] =
3814 info.spd[channel][slot][DENSITY] & 0xF;
3815 if (!
3816 (info.
3817 spd[channel][slot][MEMORY_BUS_WIDTH] &
3818 0x18))
3819 info.use_ecc = 0;
3820 }
3821
3822 gav(0x55);
3823
3824 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3825 int v = 0;
3826 for (slot = 0; slot < NUM_SLOTS; slot++)
3827 for (rank = 0; rank < NUM_RANKS; rank++)
3828 v |= info.
3829 populated_ranks[channel][slot][rank]
3830 << (2 * slot + rank);
3831 info.populated_ranks_mask[channel] = v;
3832 }
3833
3834 gav(0x55);
3835
Angel Pons16fe1e02020-07-22 16:12:33 +02003836 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837 }
3838
3839 /* after SPD */
3840 timestamp_add_now(102);
3841
Felix Held04be2dd2018-07-29 04:53:22 +02003842 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003843
3844 collect_system_info(&info);
3845 calculate_timings(&info);
3846
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003847 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003848 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003849 if (x2ca8 == 0 && (reg8 & 0x80)) {
3850 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3851 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3852 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3853 */
3854
3855 /* Clear bit7. */
3856
3857 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3858 (reg8 & ~(1 << 7)));
3859
3860 printk(BIOS_INFO,
3861 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003862 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863 }
3864 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003865
3866 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003867 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3868 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869
3870 compute_derived_timings(&info);
3871
3872 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003873 gav(MCHBAR8(0x164));
3874 MCHBAR8(0x164) = 0x26;
3875 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876 }
3877
Felix Held04be2dd2018-07-29 04:53:22 +02003878 MCHBAR32_OR(0x18b4, 0x210000);
3879 MCHBAR32_OR(0x1890, 0x2000000);
3880 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003881
Angel Ponsa457e352020-07-22 18:17:33 +02003882 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3883 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884
Felix Held04be2dd2018-07-29 04:53:22 +02003885 gav(MCHBAR16(0x2c10));
3886 MCHBAR16(0x2c10) = 0x412;
3887 gav(MCHBAR16(0x2c10));
3888 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889
Felix Held04be2dd2018-07-29 04:53:22 +02003890 gav(MCHBAR8(0x2ca8)); // !!!!
3891 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892
Angel Ponsa457e352020-07-22 18:17:33 +02003893 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3894 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003895 gav(MCHBAR32(0x1c04)); // !!!!
3896 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003897
3898 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003899 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900 }
3901
Felix Held04be2dd2018-07-29 04:53:22 +02003902 MCHBAR32(0x18d8) = 0x120000;
3903 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003904 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3905 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003906 MCHBAR32(0x18d8) = 0x40000;
3907 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003908 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3909 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003910 MCHBAR32(0x18d8) = 0x180000;
3911 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003912 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3913 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003915
Felix Held04be2dd2018-07-29 04:53:22 +02003916 gav(MCHBAR32(0x18dc)); // !!!!
3917 MCHBAR32(0x18dc) = 0x3;
3918 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
3920 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003921 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922 }
3923
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003925 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003926 MCHBAR32(0x1a10) = 0x4200010e;
3927 MCHBAR32_OR(0x18b8, 0x200);
3928 gav(MCHBAR32(0x1918)); // !!!!
3929 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930
Felix Held04be2dd2018-07-29 04:53:22 +02003931 gav(MCHBAR32(0x18b8)); // !!!!
3932 MCHBAR32(0x18b8) = 0xe00;
3933 gav(MCHBAR32(0x182c)); // !!!!
3934 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003935 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3936 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3938 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003939
Felix Held04be2dd2018-07-29 04:53:22 +02003940 MCHBAR32_AND(0x18b4, 0xffff7fff);
3941 gav(MCHBAR32(0x1a68)); // !!!!
3942 MCHBAR32(0x1a68) = 0x343800;
3943 gav(MCHBAR32(0x1e68)); // !!!!
3944 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945
3946 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003947 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948 }
3949
Angel Pons08143572020-07-22 17:47:06 +02003950 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3951 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3952 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3953 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3954 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003955 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3956 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003957 gav(MCHBAR32(0x1af0)); // !!!!
3958 gav(MCHBAR32(0x1af0)); // !!!!
3959 MCHBAR32(0x1af0) = 0x1f020003;
3960 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003961
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003962 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003963 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003964 }
3965
Felix Held04be2dd2018-07-29 04:53:22 +02003966 gav(MCHBAR32(0x1890)); // !!!!
3967 MCHBAR32(0x1890) = 0x80102;
3968 gav(MCHBAR32(0x18b4)); // !!!!
3969 MCHBAR32(0x18b4) = 0x216000;
3970 MCHBAR32(0x18a4) = 0x22222222;
3971 MCHBAR32(0x18a8) = 0x22222222;
3972 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003973
3974 udelay(1000);
3975
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003976 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003977
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003978 if (x2ca8 == 0) {
3979 int j;
3980 if (s3resume && info.cached_training) {
3981 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003982 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003983 info.cached_training->reg2ca9_bit0);
3984 for (i = 0; i < 2; i++)
3985 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003986 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003987 i, j, info.cached_training->reg274265[i][j]);
3988 } else {
3989 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02003990 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003991 info.training.reg2ca9_bit0);
3992 for (i = 0; i < 2; i++)
3993 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02003994 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003995 i, j, info.training.reg274265[i][j]);
3996 }
3997
3998 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003999
4000 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004001 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004002 }
4003
4004 udelay(1000);
4005
4006 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004007 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004008 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004009 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4010 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4011 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004012
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004013 MCHBAR8(0x1150);
4014 MCHBAR8(0x1151);
4015 MCHBAR8(0x1022);
4016 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004017 MCHBAR32(0x1300) = 0x60606060;
4018 MCHBAR32(0x1304) = 0x60606060;
4019 MCHBAR32(0x1308) = 0x78797a7b;
4020 MCHBAR32(0x130c) = 0x7c7d7e7f;
4021 MCHBAR32(0x1310) = 0x60606060;
4022 MCHBAR32(0x1314) = 0x60606060;
4023 MCHBAR32(0x1318) = 0x60606060;
4024 MCHBAR32(0x131c) = 0x60606060;
4025 MCHBAR32(0x1320) = 0x50515253;
4026 MCHBAR32(0x1324) = 0x54555657;
4027 MCHBAR32(0x1328) = 0x58595a5b;
4028 MCHBAR32(0x132c) = 0x5c5d5e5f;
4029 MCHBAR32(0x1330) = 0x40414243;
4030 MCHBAR32(0x1334) = 0x44454647;
4031 MCHBAR32(0x1338) = 0x48494a4b;
4032 MCHBAR32(0x133c) = 0x4c4d4e4f;
4033 MCHBAR32(0x1340) = 0x30313233;
4034 MCHBAR32(0x1344) = 0x34353637;
4035 MCHBAR32(0x1348) = 0x38393a3b;
4036 MCHBAR32(0x134c) = 0x3c3d3e3f;
4037 MCHBAR32(0x1350) = 0x20212223;
4038 MCHBAR32(0x1354) = 0x24252627;
4039 MCHBAR32(0x1358) = 0x28292a2b;
4040 MCHBAR32(0x135c) = 0x2c2d2e2f;
4041 MCHBAR32(0x1360) = 0x10111213;
4042 MCHBAR32(0x1364) = 0x14151617;
4043 MCHBAR32(0x1368) = 0x18191a1b;
4044 MCHBAR32(0x136c) = 0x1c1d1e1f;
4045 MCHBAR32(0x1370) = 0x10203;
4046 MCHBAR32(0x1374) = 0x4050607;
4047 MCHBAR32(0x1378) = 0x8090a0b;
4048 MCHBAR32(0x137c) = 0xc0d0e0f;
4049 MCHBAR8(0x11cc) = 0x4e;
4050 MCHBAR32(0x1110) = 0x73970404;
4051 MCHBAR32(0x1114) = 0x72960404;
4052 MCHBAR32(0x1118) = 0x6f950404;
4053 MCHBAR32(0x111c) = 0x6d940404;
4054 MCHBAR32(0x1120) = 0x6a930404;
4055 MCHBAR32(0x1124) = 0x68a41404;
4056 MCHBAR32(0x1128) = 0x66a21404;
4057 MCHBAR32(0x112c) = 0x63a01404;
4058 MCHBAR32(0x1130) = 0x609e1404;
4059 MCHBAR32(0x1134) = 0x5f9c1404;
4060 MCHBAR32(0x1138) = 0x5c961404;
4061 MCHBAR32(0x113c) = 0x58a02404;
4062 MCHBAR32(0x1140) = 0x54942404;
4063 MCHBAR32(0x1190) = 0x900080a;
4064 MCHBAR16(0x11c0) = 0xc40b;
4065 MCHBAR16(0x11c2) = 0x303;
4066 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004067 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004068 MCHBAR32(0x11b8) = 0x70c3000;
4069 MCHBAR8(0x11ec) = 0xa;
4070 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004071 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004072 MCHBAR16(0x11ca) = 0xfa;
4073 MCHBAR32(0x11e4) = 0x4e20;
4074 MCHBAR8(0x11bc) = 0xf;
4075 MCHBAR16(0x11da) = 0x19;
4076 MCHBAR16(0x11ba) = 0x470c;
4077 MCHBAR32(0x1680) = 0xe6ffe4ff;
4078 MCHBAR32(0x1684) = 0xdeffdaff;
4079 MCHBAR32(0x1688) = 0xd4ffd0ff;
4080 MCHBAR32(0x168c) = 0xccffc6ff;
4081 MCHBAR32(0x1690) = 0xc0ffbeff;
4082 MCHBAR32(0x1694) = 0xb8ffb0ff;
4083 MCHBAR32(0x1698) = 0xa8ff0000;
4084 MCHBAR32(0x169c) = 0xc00;
4085 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004086 }
4087
Felix Held04be2dd2018-07-29 04:53:22 +02004088 MCHBAR32(0x124c) = 0x15040d00;
4089 MCHBAR32(0x1250) = 0x7f0000;
4090 MCHBAR32(0x1254) = 0x1e220004;
4091 MCHBAR32(0x1258) = 0x4000004;
4092 MCHBAR32(0x1278) = 0x0;
4093 MCHBAR32(0x125c) = 0x0;
4094 MCHBAR32(0x1260) = 0x0;
4095 MCHBAR32(0x1264) = 0x0;
4096 MCHBAR32(0x1268) = 0x0;
4097 MCHBAR32(0x126c) = 0x0;
4098 MCHBAR32(0x1270) = 0x0;
4099 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004100 }
4101
4102 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004103 MCHBAR16(0x1214) = 0x320;
4104 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004105 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4106 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004107 MCHBAR32(0x1400) = 0x13040020;
4108 MCHBAR32(0x1404) = 0xe090120;
4109 MCHBAR32(0x1408) = 0x5120220;
4110 MCHBAR32(0x140c) = 0x5120330;
4111 MCHBAR32(0x1410) = 0xe090220;
4112 MCHBAR32(0x1414) = 0x1010001;
4113 MCHBAR32(0x1418) = 0x1110000;
4114 MCHBAR32(0x141c) = 0x9020020;
4115 MCHBAR32(0x1420) = 0xd090220;
4116 MCHBAR32(0x1424) = 0x2090220;
4117 MCHBAR32(0x1428) = 0x2090330;
4118 MCHBAR32(0x142c) = 0xd090220;
4119 MCHBAR32(0x1430) = 0x1010001;
4120 MCHBAR32(0x1434) = 0x1110000;
4121 MCHBAR32(0x1438) = 0x11040020;
4122 MCHBAR32(0x143c) = 0x4030220;
4123 MCHBAR32(0x1440) = 0x1060220;
4124 MCHBAR32(0x1444) = 0x1060330;
4125 MCHBAR32(0x1448) = 0x4030220;
4126 MCHBAR32(0x144c) = 0x1010001;
4127 MCHBAR32(0x1450) = 0x1110000;
4128 MCHBAR32(0x1454) = 0x4010020;
4129 MCHBAR32(0x1458) = 0xb090220;
4130 MCHBAR32(0x145c) = 0x1090220;
4131 MCHBAR32(0x1460) = 0x1090330;
4132 MCHBAR32(0x1464) = 0xb090220;
4133 MCHBAR32(0x1468) = 0x1010001;
4134 MCHBAR32(0x146c) = 0x1110000;
4135 MCHBAR32(0x1470) = 0xf040020;
4136 MCHBAR32(0x1474) = 0xa090220;
4137 MCHBAR32(0x1478) = 0x1120220;
4138 MCHBAR32(0x147c) = 0x1120330;
4139 MCHBAR32(0x1480) = 0xa090220;
4140 MCHBAR32(0x1484) = 0x1010001;
4141 MCHBAR32(0x1488) = 0x1110000;
4142 MCHBAR32(0x148c) = 0x7020020;
4143 MCHBAR32(0x1490) = 0x1010220;
4144 MCHBAR32(0x1494) = 0x10210;
4145 MCHBAR32(0x1498) = 0x10320;
4146 MCHBAR32(0x149c) = 0x1010220;
4147 MCHBAR32(0x14a0) = 0x1010001;
4148 MCHBAR32(0x14a4) = 0x1110000;
4149 MCHBAR32(0x14a8) = 0xd040020;
4150 MCHBAR32(0x14ac) = 0x8090220;
4151 MCHBAR32(0x14b0) = 0x1111310;
4152 MCHBAR32(0x14b4) = 0x1111420;
4153 MCHBAR32(0x14b8) = 0x8090220;
4154 MCHBAR32(0x14bc) = 0x1010001;
4155 MCHBAR32(0x14c0) = 0x1110000;
4156 MCHBAR32(0x14c4) = 0x3010020;
4157 MCHBAR32(0x14c8) = 0x7090220;
4158 MCHBAR32(0x14cc) = 0x1081310;
4159 MCHBAR32(0x14d0) = 0x1081420;
4160 MCHBAR32(0x14d4) = 0x7090220;
4161 MCHBAR32(0x14d8) = 0x1010001;
4162 MCHBAR32(0x14dc) = 0x1110000;
4163 MCHBAR32(0x14e0) = 0xb040020;
4164 MCHBAR32(0x14e4) = 0x2030220;
4165 MCHBAR32(0x14e8) = 0x1051310;
4166 MCHBAR32(0x14ec) = 0x1051420;
4167 MCHBAR32(0x14f0) = 0x2030220;
4168 MCHBAR32(0x14f4) = 0x1010001;
4169 MCHBAR32(0x14f8) = 0x1110000;
4170 MCHBAR32(0x14fc) = 0x5020020;
4171 MCHBAR32(0x1500) = 0x5090220;
4172 MCHBAR32(0x1504) = 0x2071310;
4173 MCHBAR32(0x1508) = 0x2071420;
4174 MCHBAR32(0x150c) = 0x5090220;
4175 MCHBAR32(0x1510) = 0x1010001;
4176 MCHBAR32(0x1514) = 0x1110000;
4177 MCHBAR32(0x1518) = 0x7040120;
4178 MCHBAR32(0x151c) = 0x2090220;
4179 MCHBAR32(0x1520) = 0x70b1210;
4180 MCHBAR32(0x1524) = 0x70b1310;
4181 MCHBAR32(0x1528) = 0x2090220;
4182 MCHBAR32(0x152c) = 0x1010001;
4183 MCHBAR32(0x1530) = 0x1110000;
4184 MCHBAR32(0x1534) = 0x1010110;
4185 MCHBAR32(0x1538) = 0x1081310;
4186 MCHBAR32(0x153c) = 0x5041200;
4187 MCHBAR32(0x1540) = 0x5041310;
4188 MCHBAR32(0x1544) = 0x1081310;
4189 MCHBAR32(0x1548) = 0x1010001;
4190 MCHBAR32(0x154c) = 0x1110000;
4191 MCHBAR32(0x1550) = 0x1040120;
4192 MCHBAR32(0x1554) = 0x4051210;
4193 MCHBAR32(0x1558) = 0xd051200;
4194 MCHBAR32(0x155c) = 0xd051200;
4195 MCHBAR32(0x1560) = 0x4051210;
4196 MCHBAR32(0x1564) = 0x1010001;
4197 MCHBAR32(0x1568) = 0x1110000;
4198 MCHBAR16(0x1222) = 0x220a;
4199 MCHBAR16(0x123c) = 0x1fc0;
4200 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004201 }
4202
Angel Ponsc627dc92020-09-22 17:06:44 +02004203 MCHBAR32_OR(0x2c80, (1 << 24));
4204 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004205
Angel Ponsc627dc92020-09-22 17:06:44 +02004206 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004207
4208 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004209 MCHBAR8_AND(0x2ca8, ~3);
4210 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004211 /* This issues a CPU reset without resetting the platform */
4212 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004213 /* Write back the S3 state to PM1_CNT to let the reset CPU
4214 know it also needs to take the s3 path. */
4215 if (s3resume)
4216 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4217 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004218 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004219 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004220 }
Angel Ponsc627dc92020-09-22 17:06:44 +02004221 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004222
Angel Ponsc627dc92020-09-22 17:06:44 +02004223 MCHBAR32_AND(0x2c80, ~(1 << 24));
4224
Angel Pons9addda32020-07-22 18:37:32 +02004225 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02004226
4227 {
4228 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
4229 u16 x2c10 = MCHBAR16(0x2c10);
4230 u16 value = MCHBAR16(0x2c00);
4231 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
4232 value |= (1 << 7);
4233 else
4234 value &= ~(1 << 0);
4235
4236 MCHBAR16(0x2c00) = value;
4237 }
4238
4239 udelay(1000); // !!!!
4240
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004241 write_1d0(0, 0x33d, 0, 0);
4242 write_500(&info, 0, 0, 0xb61, 0, 0);
4243 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004244 MCHBAR32(0x1a30) = 0x0;
4245 MCHBAR32(0x1a34) = 0x0;
4246 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4247 (info.populated_ranks[0][0][0] * 0xa0);
4248 MCHBAR16(0x616) = 0x26a;
4249 MCHBAR32(0x134) = 0x856000;
4250 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004251 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4252 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004254 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4255 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004256 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004258 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4259 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004260 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4261 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4262 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4263 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4264 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4265 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4266 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4267 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4268 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4269 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270 }
4271
4272 write_1d0(0x4, 0x151, 4, 1);
4273 write_1d0(0, 0x142, 3, 1);
4274 rdmsr(0x1ac); // !!!!
4275 write_500(&info, 1, 1, 0x6b3, 4, 1);
4276 write_500(&info, 1, 1, 0x6cf, 4, 1);
4277
Angel Pons244f4552021-01-15 20:41:36 +01004278 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004279
4280 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4281 populated_ranks[0]
4282 [0][0]) << 0),
4283 0x1d1, 3, 1);
4284 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004285 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4286 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004287 }
4288
4289 set_334(0);
4290
4291 program_base_timings(&info);
4292
Felix Held04be2dd2018-07-29 04:53:22 +02004293 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004294
4295 write_1d0(0x2, 0x1d5, 2, 1);
4296 write_1d0(0x20, 0x166, 7, 1);
4297 write_1d0(0x0, 0xeb, 3, 1);
4298 write_1d0(0x0, 0xf3, 6, 1);
4299
4300 for (channel = 0; channel < NUM_CHANNELS; channel++)
4301 for (lane = 0; lane < 9; lane++) {
4302 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4303 u8 a;
4304 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4305 write_500(&info, channel, a, addr, 6, 1);
4306 }
4307
4308 udelay(1000);
4309
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004310 if (s3resume) {
4311 if (info.cached_training == NULL) {
4312 u32 reg32;
4313 printk(BIOS_ERR,
4314 "Couldn't find training data. Rebooting\n");
4315 reg32 = inl(DEFAULT_PMBASE + 0x04);
4316 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004317 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004318 }
4319 int tm;
4320 info.training = *info.cached_training;
4321 for (tm = 0; tm < 4; tm++)
4322 for (channel = 0; channel < NUM_CHANNELS; channel++)
4323 for (slot = 0; slot < NUM_SLOTS; slot++)
4324 for (rank = 0; rank < NUM_RANKS; rank++)
4325 for (lane = 0; lane < 9; lane++)
4326 write_500(&info,
4327 channel,
4328 info.training.
4329 lane_timings
4330 [tm][channel]
4331 [slot][rank]
4332 [lane],
4333 get_timing_register_addr
4334 (lane, tm,
4335 slot, rank),
4336 9, 0);
4337 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4338 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4339 }
4340
Felix Heldf83d80b2018-07-29 05:30:30 +02004341 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004342 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02004343 MCHBAR8_OR(0x1f0, 0x1);
4344 while (MCHBAR8(0x1f0) & 1)
4345 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004346
4347 program_board_delay(&info);
4348
Felix Held04be2dd2018-07-29 04:53:22 +02004349 MCHBAR8(0x5ff) = 0x0;
4350 MCHBAR8(0x5ff) = 0x80;
4351 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004352
Felix Held04be2dd2018-07-29 04:53:22 +02004353 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004354 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004355 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02004356
4357 rmw_1d0(0x14b, 0x47, 0x30, 7);
4358 rmw_1d0(0xd6, 0x38, 7, 6);
4359 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004360
4361 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004362 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004363
Angel Ponsc627dc92020-09-22 17:06:44 +02004364 rmw_1d0(0x116, 0xe, 0, 4);
4365 rmw_1d0(0xae, 0x3e, 0, 6);
4366 rmw_1d0(0x300, 0x3e, 0, 6);
4367 MCHBAR16_AND(0x356, 0x7fff);
4368 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02004369 MCHBAR32_AND(0x140, ~0x07000000);
4370 MCHBAR32_AND(0x138, ~0x07000000);
4371 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004372 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004373 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004374 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004375
Angel Pons26681912021-01-15 21:36:28 +01004376 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004377 {
Angel Pons26681912021-01-15 21:36:28 +01004378 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
4379 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
4380 value_a1 = val_xa1;
4381 rmw_1d0(0x320, 0x38, val_2f3, 6);
4382 rmw_1d0(0x14b, 0x78, val_xa1, 7);
4383 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004384 }
4385
4386 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004387 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004388
Angel Pons244f4552021-01-15 20:41:36 +01004389 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01004390 {
4391 if ((MCHBAR32(0x144) & 0x1f) < 0x13)
4392 value_a1 += 2;
4393 else
4394 value_a1 += 1;
4395
4396 if (value_a1 > 7)
4397 value_a1 = 7;
4398
4399 write_1d0(2, 0xae, 6, 1);
4400 write_1d0(2, 0x300, 6, 1);
4401 write_1d0(value_a1, 0x121, 3, 1);
4402 rmw_1d0(0xd6, 0x38, 4, 6);
4403 rmw_1d0(0x328, 0x38, 4, 6);
4404 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004405
4406 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004407 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004408
Felix Held04be2dd2018-07-29 04:53:22 +02004409 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4410 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004411 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004412 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02004413
4414 {
Angel Pons26681912021-01-15 21:36:28 +01004415 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02004416 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4417 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01004418 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02004419 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004420
4421 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01004422 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004423
4424 set_334(1);
4425
Felix Held04be2dd2018-07-29 04:53:22 +02004426 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004427
4428 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4429 write_500(&info, channel,
4430 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4431 1);
4432 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4433 }
Felix Held04be2dd2018-07-29 04:53:22 +02004434 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4435 MCHBAR16(0x6c0) = 0x14a0;
4436 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4437 MCHBAR16(0x232) = 0x8;
4438 /* 0x40004 or 0 depending on ? */
4439 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4440 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4441 MCHBAR32(0x128) = 0x2150d05;
4442 MCHBAR8(0x12c) = 0x1f;
4443 MCHBAR8(0x12d) = 0x56;
4444 MCHBAR8(0x12e) = 0x31;
4445 MCHBAR8(0x12f) = 0x0;
4446 MCHBAR8(0x271) = 0x2;
4447 MCHBAR8(0x671) = 0x2;
4448 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004449 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004450 MCHBAR32(0x294 + (channel << 10)) =
4451 (info.populated_ranks_mask[channel] & 3) << 16;
4452 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4453 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004454 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004455 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4456 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004457
4458 if (!s3resume)
4459 jedec_init(&info);
4460
4461 int totalrank = 0;
4462 for (channel = 0; channel < NUM_CHANNELS; channel++)
4463 for (slot = 0; slot < NUM_SLOTS; slot++)
4464 for (rank = 0; rank < NUM_RANKS; rank++)
4465 if (info.populated_ranks[channel][slot][rank]) {
4466 jedec_read(&info, channel, slot, rank,
4467 totalrank, 0xa, 0x400);
4468 totalrank++;
4469 }
4470
Felix Held04be2dd2018-07-29 04:53:22 +02004471 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004472
Angel Ponsc627dc92020-09-22 17:06:44 +02004473 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
4474 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475
4476 if (!s3resume) {
4477 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004478 MCHBAR32(0x294 + (channel << 10)) =
4479 (info.populated_ranks_mask[channel] & 3) << 16;
4480 MCHBAR16(0x298 + (channel << 10)) =
4481 info.populated_ranks[channel][0][0] |
4482 (info.populated_ranks[channel][0][1] << 5);
4483 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004485 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004486
4487 {
4488 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004489 a = MCHBAR8(0x243);
4490 b = MCHBAR8(0x643);
4491 MCHBAR8(0x243) = a | 2;
4492 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493 }
4494
4495 write_1d0(7, 0x19b, 3, 1);
4496 write_1d0(7, 0x1c0, 3, 1);
4497 write_1d0(4, 0x1c6, 4, 1);
4498 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02004499 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02004500 MCHBAR32(0x584) = 0xfffff;
4501 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004502
4503 for (channel = 0; channel < NUM_CHANNELS; channel++)
4504 for (slot = 0; slot < NUM_SLOTS; slot++)
4505 for (rank = 0; rank < NUM_RANKS; rank++)
4506 if (info.
4507 populated_ranks[channel][slot]
4508 [rank])
4509 config_rank(&info, s3resume,
4510 channel, slot,
4511 rank);
4512
Felix Held04be2dd2018-07-29 04:53:22 +02004513 MCHBAR8(0x243) = 0x1;
4514 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004515 }
4516
4517 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004518 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519 write_26c(0, 0x820);
4520 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004521 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522 /* end */
4523
4524 if (s3resume) {
4525 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004526 MCHBAR32(0x294 + (channel << 10)) =
4527 (info.populated_ranks_mask[channel] & 3) << 16;
4528 MCHBAR16(0x298 + (channel << 10)) =
4529 info.populated_ranks[channel][0][0] |
4530 (info.populated_ranks[channel][0][1] << 5);
4531 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004532 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004533 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004534 }
4535
Felix Held04be2dd2018-07-29 04:53:22 +02004536 MCHBAR32_AND(0xfa4, ~0x01000002);
4537 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004538
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004539 /* Before training. */
4540 timestamp_add_now(103);
4541
4542 if (!s3resume)
4543 ram_training(&info);
4544
4545 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004546 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547
4548 dump_timings(&info);
4549
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550 program_modules_memory_map(&info, 0);
4551 program_total_memory_map(&info);
4552
4553 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004554 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004555 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004556 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004558 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 else
Felix Held04be2dd2018-07-29 04:53:22 +02004560 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561
Felix Held04be2dd2018-07-29 04:53:22 +02004562 MCHBAR32_AND(0xfac, ~0x80000000);
4563 MCHBAR32(0xfb4) = 0x4800;
4564 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4565 MCHBAR32(0xe94) = 0x7ffff;
4566 MCHBAR32(0xfc0) = 0x80002040;
4567 MCHBAR32(0xfc4) = 0x701246;
4568 MCHBAR8_AND(0xfc8, ~0x70);
4569 MCHBAR32_OR(0xe5c, 0x1000000);
4570 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4571 MCHBAR32(0x50) = 0x700b0;
4572 MCHBAR32(0x3c) = 0x10;
4573 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4574 MCHBAR8_OR(0xff4, 0x2);
4575 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4578 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4579 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004581 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4582 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4583 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585 {
4586 u32 eax;
4587
4588 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004589 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4590 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4591 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592 }
4593
4594 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004597 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598 else
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600
Felix Held04be2dd2018-07-29 04:53:22 +02004601 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004602
Felix Held04be2dd2018-07-29 04:53:22 +02004603 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004605 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004606 else
Felix Held04be2dd2018-07-29 04:53:22 +02004607 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004608 }
4609
Felix Held04be2dd2018-07-29 04:53:22 +02004610 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004611
4612 {
4613 u8 al;
4614 al = 0xd;
4615 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4616 al += 2;
4617 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004618 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004619 }
4620
4621 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004622 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4623 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4624 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4625 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626 }
4627 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004628 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004629 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004630 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02004631 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004632 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004633 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR8_OR(0x1210, 2);
4635 MCHBAR32(0x1200) = 0x8800440;
4636 MCHBAR32(0x1204) = 0x53ff0453;
4637 MCHBAR32(0x1208) = 0x19002043;
4638 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639
4640 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR16(0x1214) = 0x220;
4642 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 }
4644
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR8_OR(0x1214, 0x4);
4646 MCHBAR8(0x120c) = 0x1;
4647 MCHBAR8(0x1218) = 0x3;
4648 MCHBAR8(0x121a) = 0x3;
4649 MCHBAR8(0x121c) = 0x3;
4650 MCHBAR16(0xc14) = 0x0;
4651 MCHBAR16(0xc20) = 0x0;
4652 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653
4654 /* revision dependent here. */
4655
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657
4658 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660
Felix Held04be2dd2018-07-29 04:53:22 +02004661 MCHBAR16_OR(0x1230, 0x8000);
4662 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
4664 u8 bl, ebpb;
4665 u16 reg_1020;
4666
Felix Held04be2dd2018-07-29 04:53:22 +02004667 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4668 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004669
Felix Held04be2dd2018-07-29 04:53:22 +02004670 MCHBAR32(0x1000) = 0x100;
4671 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004672
4673 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675 bl = reg_1020 >> 8;
4676 ebpb = reg_1020 & 0xff;
4677 } else {
4678 ebpb = 0;
4679 bl = 8;
4680 }
4681
4682 rdmsr(0x1a2);
4683
Felix Held04be2dd2018-07-29 04:53:22 +02004684 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004685
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004687
Felix Held04be2dd2018-07-29 04:53:22 +02004688 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004689
Felix Held04be2dd2018-07-29 04:53:22 +02004690 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4693 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694 }
4695
4696 setup_heci_uma(&info);
4697
4698 if (info.uma_enabled) {
4699 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004700 MCHBAR32_OR(0x11b0, 0x4000);
4701 MCHBAR32_OR(0x11b4, 0x4000);
4702 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
Felix Held04be2dd2018-07-29 04:53:22 +02004704 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4705 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4706 MCHBAR16_OR(0x1170, 0x1000);
4707
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004708 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004709
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004711 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004712 ;
4713 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004714 }
4715
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004716 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4717 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004718 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004719 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721 udelay(1000);
4722 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004723 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4724
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725 if (!s3resume)
4726 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004727 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004728 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02004729 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004730
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004731 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004732 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004733 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004734}