blob: daaa96a9ccca4cafe43d6299f55a8f944b803daf [file] [log] [blame]
Patrick Georgi02363b52020-05-05 20:48:50 +02001/* This file is part of the coreboot project. */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002/*
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010013 */
14
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +010016#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010017#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020019#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020020#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010021#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010022#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020024#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010025#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020026#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020028#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010029#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010030#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010031#include <timestamp.h>
32#include <cpu/x86/mtrr.h>
33#include <cpu/intel/speedstep.h>
34#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010035#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020036#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020037#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010038#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020039#include <types.h>
40
41#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010042#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020043#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020044#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010045
46#define NORTHBRIDGE PCI_DEV(0, 0, 0)
47#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
48#define GMA PCI_DEV (0, 0x2, 0x0)
49#define HECIDEV PCI_DEV(0, 0x16, 0)
50#define HECIBAR 0x10
51
52#define FOR_ALL_RANKS \
53 for (channel = 0; channel < NUM_CHANNELS; channel++) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++)
56
57#define FOR_POPULATED_RANKS \
58 for (channel = 0; channel < NUM_CHANNELS; channel++) \
59 for (slot = 0; slot < NUM_SLOTS; slot++) \
60 for (rank = 0; rank < NUM_RANKS; rank++) \
61 if (info->populated_ranks[channel][slot][rank])
62
63#define FOR_POPULATED_RANKS_BACKWARDS \
64 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
65 for (slot = 0; slot < NUM_SLOTS; slot++) \
66 for (rank = 0; rank < NUM_RANKS; rank++) \
67 if (info->populated_ranks[channel][slot][rank])
68
69/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
70typedef struct {
71 u8 smallest;
72 u8 largest;
73} timing_bounds_t[2][2][2][9];
74
Arthur Heymansdc71e252018-01-29 10:14:48 +010075#define MRC_CACHE_VERSION 1
76
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010077struct ram_training {
78 /* [TM][CHANNEL][SLOT][RANK][LANE] */
79 u16 lane_timings[4][2][2][2][9];
80 u16 reg_178;
81 u16 reg_10b;
82
83 u8 reg178_center;
84 u8 reg178_smallest;
85 u8 reg178_largest;
86 timing_bounds_t timing_bounds[2];
87 u16 timing_offset[2][2][2][9];
88 u16 timing2_offset[2][2][2][9];
89 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010090 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
91 u8 reg2ca9_bit0;
92 u32 reg_6dc;
93 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094};
95
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096#include <lib.h> /* Prototypes */
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098typedef struct _u128 {
99 u64 lo;
100 u64 hi;
101} u128;
102
103static void read128(u32 addr, u64 * out)
104{
105 u128 ret;
106 u128 stor;
107 asm volatile ("movdqu %%xmm0, %0\n"
108 "movdqa (%2), %%xmm0\n"
109 "movdqu %%xmm0, %1\n"
110 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
111 out[0] = ret.lo;
112 out[1] = ret.hi;
113}
114
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100115/* OK */
116static void write_1d0(u32 val, u16 addr, int bits, int flag)
117{
Felix Held04be2dd2018-07-29 04:53:22 +0200118 MCHBAR32(0x1d0) = 0;
119 while (MCHBAR32(0x1d0) & 0x800000)
120 ;
121 MCHBAR32(0x1d4) =
122 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
123 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200124 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200125 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100126}
127
128/* OK */
129static u16 read_1d0(u16 addr, int split)
130{
131 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200132 MCHBAR32(0x1d0) = 0;
133 while (MCHBAR32(0x1d0) & 0x800000)
134 ;
135 MCHBAR32(0x1d0) =
136 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
137 while (MCHBAR32(0x1d0) & 0x800000)
138 ;
139 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100140 write_1d0(0, 0x33d, 0, 0);
141 write_1d0(0, 0x33d, 0, 0);
142 val &= ((1 << split) - 1);
143 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
144 return val;
145}
146
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800147static void write32p(uintptr_t addr, uint32_t val)
148{
149 write32((void *)addr, val);
150}
151
152static uint32_t read32p(uintptr_t addr)
153{
154 return read32((void *)addr);
155}
156
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100157static void sfence(void)
158{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100159 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100160}
161
162static inline u16 get_lane_offset(int slot, int rank, int lane)
163{
164 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
165 0x452 * (lane == 8);
166}
167
168static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
169{
170 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
171 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
172}
173
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100174static u32 gav_real(int line, u32 in)
175{
176 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
177 return in;
178}
179
180#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200181
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100182struct raminfo {
183 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
184 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
185 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
186 u8 density[2][2]; /* [CHANNEL][SLOT] */
187 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
188 int rank_start[2][2][2];
189 u8 cas_latency;
190 u8 board_lane_delay[9];
191 u8 use_ecc;
192 u8 revision;
193 u8 max_supported_clock_speed_index;
194 u8 uma_enabled;
195 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
196 u8 silicon_revision;
197 u8 populated_ranks_mask[2];
198 u8 max_slots_used_in_channel;
199 u8 mode4030[2];
200 u16 avg4044[2];
201 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600202 unsigned int total_memory_mb;
203 unsigned int interleaved_part_mb;
204 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100205
206 u32 heci_bar;
207 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600208 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209
210 struct ram_training training;
211 u32 last_500_command[2];
212
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100213 u32 delay46_ps[2];
214 u32 delay54_ps[2];
215 u8 revision_flag_1;
216 u8 some_delay_1_cycle_floor;
217 u8 some_delay_2_halfcycles_ceil;
218 u8 some_delay_3_ps_rounded;
219
220 const struct ram_training *cached_training;
221};
222
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200223/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100224timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200225
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100226static void
227write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
228 int flag);
229
230/* OK */
231static u16
232read_500(struct raminfo *info, int channel, u16 addr, int split)
233{
234 u32 val;
235 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200236 MCHBAR32(0x500 + (channel << 10)) = 0;
237 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
238 ;
239 MCHBAR32(0x500 + (channel << 10)) =
240 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
241 + 0xb88 - addr);
242 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
243 ;
244 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100245 return val & ((1 << split) - 1);
246}
247
248/* OK */
249static void
250write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
251 int flag)
252{
253 if (info->last_500_command[channel] == 0x80000000) {
254 info->last_500_command[channel] = 0x40000000;
255 write_500(info, channel, 0, 0xb61, 0, 0);
256 }
Felix Held04be2dd2018-07-29 04:53:22 +0200257 MCHBAR32(0x500 + (channel << 10)) = 0;
258 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
259 ;
260 MCHBAR32(0x504 + (channel << 10)) =
261 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
262 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200263 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200264 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100265}
266
267static int rw_test(int rank)
268{
269 const u32 mask = 0xf00fc33c;
270 int ok = 0xff;
271 int i;
272 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800273 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100274 sfence();
275 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100277 sfence();
278 for (i = 0; i < 32; i++) {
279 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800280 write32p((rank << 28) | (i << 3), pat);
281 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 }
283 sfence();
284 for (i = 0; i < 32; i++) {
285 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
286 int j;
287 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 for (j = 0; j < 4; j++)
290 if (((val >> (j * 8)) & 0xff) != pat)
291 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800292 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100293 for (j = 0; j < 4; j++)
294 if (((val >> (j * 8)) & 0xff) != pat)
295 ok &= ~(16 << j);
296 }
297 sfence();
298 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800299 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100300 sfence();
301 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800302 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100303
304 return ok;
305}
306
307static void
308program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
309{
310 int lane;
311 for (lane = 0; lane < 8; lane++) {
312 write_500(info, channel,
313 base +
314 info->training.
315 lane_timings[2][channel][slot][rank][lane],
316 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
317 write_500(info, channel,
318 base +
319 info->training.
320 lane_timings[3][channel][slot][rank][lane],
321 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
322 }
323}
324
325static void write_26c(int channel, u16 si)
326{
Felix Held04be2dd2018-07-29 04:53:22 +0200327 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
328 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
329 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100330}
331
332static u32 get_580(int channel, u8 addr)
333{
334 u32 ret;
335 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200336 MCHBAR8(0x5ff) = 0x0;
337 MCHBAR8(0x5ff) = 0x80;
338 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
339 MCHBAR8_OR(0x580 + (channel << 10), 1);
340 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
341 ;
342 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100343 return ret;
344}
345
346const int cached_config = 0;
347
348#define NUM_CHANNELS 2
349#define NUM_SLOTS 2
350#define NUM_RANKS 2
351#define RANK_SHIFT 28
352#define CHANNEL_SHIFT 10
353
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100354static void seq9(struct raminfo *info, int channel, int slot, int rank)
355{
356 int i, lane;
357
358 for (i = 0; i < 2; i++)
359 for (lane = 0; lane < 8; lane++)
360 write_500(info, channel,
361 info->training.lane_timings[i +
362 1][channel][slot]
363 [rank][lane], get_timing_register_addr(lane,
364 i + 1,
365 slot,
366 rank),
367 9, 0);
368
369 write_1d0(1, 0x103, 6, 1);
370 for (lane = 0; lane < 8; lane++)
371 write_500(info, channel,
372 info->training.
373 lane_timings[0][channel][slot][rank][lane],
374 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
375
376 for (i = 0; i < 2; i++) {
377 for (lane = 0; lane < 8; lane++)
378 write_500(info, channel,
379 info->training.lane_timings[i +
380 1][channel][slot]
381 [rank][lane], get_timing_register_addr(lane,
382 i + 1,
383 slot,
384 rank),
385 9, 0);
386 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
387 }
388
389 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200390 MCHBAR8(0x5ff) = 0x0;
391 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100392 write_1d0(0x2, 0x142, 3, 1);
393 for (lane = 0; lane < 8; lane++) {
394 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
395 info->training.lane_timings[2][channel][slot][rank][lane] =
396 read_500(info, channel,
397 get_timing_register_addr(lane, 2, slot, rank), 9);
398 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
399 info->training.lane_timings[3][channel][slot][rank][lane] =
400 info->training.lane_timings[2][channel][slot][rank][lane] +
401 0x20;
402 }
403}
404
405static int count_ranks_in_channel(struct raminfo *info, int channel)
406{
407 int slot, rank;
408 int res = 0;
409 for (slot = 0; slot < NUM_SLOTS; slot++)
410 for (rank = 0; rank < NUM_SLOTS; rank++)
411 res += info->populated_ranks[channel][slot][rank];
412 return res;
413}
414
415static void
416config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
417{
418 int add;
419
420 write_1d0(0, 0x178, 7, 1);
421 seq9(info, channel, slot, rank);
422 program_timings(info, 0x80, channel, slot, rank);
423
424 if (channel == 0)
425 add = count_ranks_in_channel(info, 1);
426 else
427 add = 0;
428 if (!s3resume)
429 gav(rw_test(rank + add));
430 program_timings(info, 0x00, channel, slot, rank);
431 if (!s3resume)
432 gav(rw_test(rank + add));
433 if (!s3resume)
434 gav(rw_test(rank + add));
435 write_1d0(0, 0x142, 3, 1);
436 write_1d0(0, 0x103, 6, 1);
437
438 gav(get_580(channel, 0xc | (rank << 5)));
439 gav(read_1d0(0x142, 3));
440
Felix Held04be2dd2018-07-29 04:53:22 +0200441 MCHBAR8(0x5ff) = 0x0;
442 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100443}
444
445static void set_4cf(struct raminfo *info, int channel, u8 val)
446{
447 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
448 write_500(info, channel, val, 0x4cf, 4, 1);
449 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
450 write_500(info, channel, val, 0x659, 4, 1);
451 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
452 write_500(info, channel, val, 0x697, 4, 1);
453}
454
455static void set_334(int zero)
456{
457 int j, k, channel;
458 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
459 u32 vd8[2][16];
460
461 for (channel = 0; channel < NUM_CHANNELS; channel++) {
462 for (j = 0; j < 4; j++) {
463 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
464 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
465 u16 c;
466 if ((j == 0 || j == 3) && zero)
467 c = 0;
468 else if (j == 3)
469 c = 0x5f;
470 else
471 c = 0x5f5f;
472
473 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200474 MCHBAR32(0x138 + 8 * k) =
475 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100476 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200477 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100478 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200479 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100480 }
481
Felix Held22ca8cb2018-07-29 05:09:44 +0200482 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
483 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200484 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
485 zero ? 0 : (0x18191819 & lmask);
486 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
487 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
488 zero ? 0 : (a & lmask);
489 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
490 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100491 }
492 }
493
Felix Held04be2dd2018-07-29 04:53:22 +0200494 MCHBAR32_OR(0x130, 1);
495 while (MCHBAR8(0x130) & 1)
496 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100497}
498
499static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
500{
501 u32 v;
502 v = read_1d0(addr, split);
503 write_1d0((v & and) | or, addr, split, flag);
504}
505
506static int find_highest_bit_set(u16 val)
507{
508 int i;
509 for (i = 15; i >= 0; i--)
510 if (val & (1 << i))
511 return i;
512 return -1;
513}
514
515static int find_lowest_bit_set32(u32 val)
516{
517 int i;
518 for (i = 0; i < 32; i++)
519 if (val & (1 << i))
520 return i;
521 return -1;
522}
523
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100524enum {
525 DEVICE_TYPE = 2,
526 MODULE_TYPE = 3,
527 DENSITY = 4,
528 RANKS_AND_DQ = 7,
529 MEMORY_BUS_WIDTH = 8,
530 TIMEBASE_DIVIDEND = 10,
531 TIMEBASE_DIVISOR = 11,
532 CYCLETIME = 12,
533
534 CAS_LATENCIES_LSB = 14,
535 CAS_LATENCIES_MSB = 15,
536 CAS_LATENCY_TIME = 16,
537 THERMAL_AND_REFRESH = 31,
538 REFERENCE_RAW_CARD_USED = 62,
539 RANK1_ADDRESS_MAPPING = 63
540};
541
542static void calculate_timings(struct raminfo *info)
543{
Martin Roth468d02c2019-10-23 21:44:42 -0600544 unsigned int cycletime;
545 unsigned int cas_latency_time;
546 unsigned int supported_cas_latencies;
547 unsigned int channel, slot;
548 unsigned int clock_speed_index;
549 unsigned int min_cas_latency;
550 unsigned int cas_latency;
551 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100552
553 /* Find common CAS latency */
554 supported_cas_latencies = 0x3fe;
555 for (channel = 0; channel < NUM_CHANNELS; channel++)
556 for (slot = 0; slot < NUM_SLOTS; slot++)
557 if (info->populated_ranks[channel][slot][0])
558 supported_cas_latencies &=
559 2 *
560 (info->
561 spd[channel][slot][CAS_LATENCIES_LSB] |
562 (info->
563 spd[channel][slot][CAS_LATENCIES_MSB] <<
564 8));
565
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100566 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100567
568 cycletime = min_cycletime[max_clock_index];
569 cas_latency_time = min_cas_latency_time[max_clock_index];
570
571 for (channel = 0; channel < NUM_CHANNELS; channel++)
572 for (slot = 0; slot < NUM_SLOTS; slot++)
573 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600574 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100575 timebase =
576 1000 *
577 info->
578 spd[channel][slot][TIMEBASE_DIVIDEND] /
579 info->spd[channel][slot][TIMEBASE_DIVISOR];
580 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100581 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100582 timebase *
583 info->spd[channel][slot][CYCLETIME]);
584 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100585 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100586 timebase *
587 info->
588 spd[channel][slot][CAS_LATENCY_TIME]);
589 }
Jacob Garber3c193822019-06-10 18:23:32 -0600590 if (cycletime > min_cycletime[0])
591 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100592 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
593 if (cycletime == min_cycletime[clock_speed_index])
594 break;
595 if (cycletime > min_cycletime[clock_speed_index]) {
596 clock_speed_index--;
597 cycletime = min_cycletime[clock_speed_index];
598 break;
599 }
600 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100601 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100602 cas_latency = 0;
603 while (supported_cas_latencies) {
604 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
605 if (cas_latency <= min_cas_latency)
606 break;
607 supported_cas_latencies &=
608 ~(1 << find_highest_bit_set(supported_cas_latencies));
609 }
610
611 if (cas_latency != min_cas_latency && clock_speed_index)
612 clock_speed_index--;
613
614 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
615 die("Couldn't configure DRAM");
616 info->clock_speed_index = clock_speed_index;
617 info->cas_latency = cas_latency;
618}
619
620static void program_base_timings(struct raminfo *info)
621{
Martin Roth468d02c2019-10-23 21:44:42 -0600622 unsigned int channel;
623 unsigned int slot, rank, lane;
624 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100625 int i;
626
627 extended_silicon_revision = info->silicon_revision;
628 if (info->silicon_revision == 0)
629 for (channel = 0; channel < NUM_CHANNELS; channel++)
630 for (slot = 0; slot < NUM_SLOTS; slot++)
631 if ((info->
632 spd[channel][slot][MODULE_TYPE] & 0xF) ==
633 3)
634 extended_silicon_revision = 4;
635
636 for (channel = 0; channel < NUM_CHANNELS; channel++) {
637 for (slot = 0; slot < NUM_SLOTS; slot++)
638 for (rank = 0; rank < NUM_SLOTS; rank++) {
639 int card_timing_2;
640 if (!info->populated_ranks[channel][slot][rank])
641 continue;
642
643 for (lane = 0; lane < 9; lane++) {
644 int tm_reg;
645 int card_timing;
646
647 card_timing = 0;
648 if ((info->
649 spd[channel][slot][MODULE_TYPE] &
650 0xF) == 3) {
651 int reference_card;
652 reference_card =
653 info->
654 spd[channel][slot]
655 [REFERENCE_RAW_CARD_USED] &
656 0x1f;
657 if (reference_card == 3)
658 card_timing =
659 u16_ffd1188[0][lane]
660 [info->
661 clock_speed_index];
662 if (reference_card == 5)
663 card_timing =
664 u16_ffd1188[1][lane]
665 [info->
666 clock_speed_index];
667 }
668
669 info->training.
670 lane_timings[0][channel][slot][rank]
671 [lane] =
672 u8_FFFD1218[info->
673 clock_speed_index];
674 info->training.
675 lane_timings[1][channel][slot][rank]
676 [lane] = 256;
677
678 for (tm_reg = 2; tm_reg < 4; tm_reg++)
679 info->training.
680 lane_timings[tm_reg]
681 [channel][slot][rank][lane]
682 =
683 u8_FFFD1240[channel]
684 [extended_silicon_revision]
685 [lane][2 * slot +
686 rank][info->
687 clock_speed_index]
688 + info->max4048[channel]
689 +
690 u8_FFFD0C78[channel]
691 [extended_silicon_revision]
692 [info->
693 mode4030[channel]][slot]
694 [rank][info->
695 clock_speed_index]
696 + card_timing;
697 for (tm_reg = 0; tm_reg < 4; tm_reg++)
698 write_500(info, channel,
699 info->training.
700 lane_timings[tm_reg]
701 [channel][slot][rank]
702 [lane],
703 get_timing_register_addr
704 (lane, tm_reg, slot,
705 rank), 9, 0);
706 }
707
708 card_timing_2 = 0;
709 if (!(extended_silicon_revision != 4
710 || (info->
711 populated_ranks_mask[channel] & 5) ==
712 5)) {
713 if ((info->
714 spd[channel][slot]
715 [REFERENCE_RAW_CARD_USED] & 0x1F)
716 == 3)
717 card_timing_2 =
718 u16_FFFE0EB8[0][info->
719 clock_speed_index];
720 if ((info->
721 spd[channel][slot]
722 [REFERENCE_RAW_CARD_USED] & 0x1F)
723 == 5)
724 card_timing_2 =
725 u16_FFFE0EB8[1][info->
726 clock_speed_index];
727 }
728
729 for (i = 0; i < 3; i++)
730 write_500(info, channel,
731 (card_timing_2 +
732 info->max4048[channel]
733 +
734 u8_FFFD0EF8[channel]
735 [extended_silicon_revision]
736 [info->
737 mode4030[channel]][info->
738 clock_speed_index]),
739 u16_fffd0c50[i][slot][rank],
740 8, 1);
741 write_500(info, channel,
742 (info->max4048[channel] +
743 u8_FFFD0C78[channel]
744 [extended_silicon_revision][info->
745 mode4030
746 [channel]]
747 [slot][rank][info->
748 clock_speed_index]),
749 u16_fffd0c70[slot][rank], 7, 1);
750 }
751 if (!info->populated_ranks_mask[channel])
752 continue;
753 for (i = 0; i < 3; i++)
754 write_500(info, channel,
755 (info->max4048[channel] +
756 info->avg4044[channel]
757 +
758 u8_FFFD17E0[channel]
759 [extended_silicon_revision][info->
760 mode4030
761 [channel]][info->
762 clock_speed_index]),
763 u16_fffd0c68[i], 8, 1);
764 }
765}
766
767static unsigned int fsbcycle_ps(struct raminfo *info)
768{
769 return 900000 / info->fsb_frequency;
770}
771
772/* The time of DDR transfer in ps. */
773static unsigned int halfcycle_ps(struct raminfo *info)
774{
775 return 3750 / (info->clock_speed_index + 3);
776}
777
778/* The time of clock cycle in ps. */
779static unsigned int cycle_ps(struct raminfo *info)
780{
781 return 2 * halfcycle_ps(info);
782}
783
784/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600785static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786{
787 return (info->clock_speed_index + 3) * 120;
788}
789
790/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600791static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100792{
793 return 100 * frequency_11(info) / 9;
794}
795
Martin Roth468d02c2019-10-23 21:44:42 -0600796static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100797{
798 return (frequency_11(info) * 2) * ps / 900000;
799}
800
Martin Roth468d02c2019-10-23 21:44:42 -0600801static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100802{
803 return (frequency_11(info)) * ns / 900;
804}
805
806static void compute_derived_timings(struct raminfo *info)
807{
Martin Roth468d02c2019-10-23 21:44:42 -0600808 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100809 int extended_silicon_revision;
810 int some_delay_1_ps;
811 int some_delay_2_ps;
812 int some_delay_2_halfcycles_ceil;
813 int some_delay_2_halfcycles_floor;
814 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100815 int some_delay_3_ps_rounded;
816 int some_delay_1_cycle_ceil;
817 int some_delay_1_cycle_floor;
818
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100819 some_delay_3_ps_rounded = 0;
820 extended_silicon_revision = info->silicon_revision;
821 if (!info->silicon_revision)
822 for (channel = 0; channel < NUM_CHANNELS; channel++)
823 for (slot = 0; slot < NUM_SLOTS; slot++)
824 if ((info->
825 spd[channel][slot][MODULE_TYPE] & 0xF) ==
826 3)
827 extended_silicon_revision = 4;
828 if (info->board_lane_delay[7] < 5)
829 info->board_lane_delay[7] = 5;
830 info->revision_flag_1 = 2;
831 if (info->silicon_revision == 2 || info->silicon_revision == 3)
832 info->revision_flag_1 = 0;
833 if (info->revision < 16)
834 info->revision_flag_1 = 0;
835
836 if (info->revision < 8)
837 info->revision_flag_1 = 0;
838 if (info->revision >= 8 && (info->silicon_revision == 0
839 || info->silicon_revision == 1))
840 some_delay_2_ps = 735;
841 else
842 some_delay_2_ps = 750;
843
844 if (info->revision >= 0x10 && (info->silicon_revision == 0
845 || info->silicon_revision == 1))
846 some_delay_1_ps = 3929;
847 else
848 some_delay_1_ps = 3490;
849
850 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
851 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
852 if (some_delay_1_ps % cycle_ps(info))
853 some_delay_1_cycle_ceil++;
854 else
855 some_delay_1_cycle_floor--;
856 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
857 if (info->revision_flag_1)
858 some_delay_2_ps = halfcycle_ps(info) >> 6;
859 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100860 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100861 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
862 375;
863 some_delay_3_ps =
864 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
865 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200866 if (some_delay_3_ps >= 150) {
867 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100868 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200869 some_delay_3_ps_rounded =
870 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
871 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100872 }
873 some_delay_2_halfcycles_ceil =
874 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
875 2 * (some_delay_1_cycle_ceil - 1);
876 if (info->revision_flag_1 && some_delay_3_ps < 150)
877 some_delay_2_halfcycles_ceil++;
878 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
879 if (info->revision < 0x10)
880 some_delay_2_halfcycles_floor =
881 some_delay_2_halfcycles_ceil - 1;
882 if (!info->revision_flag_1)
883 some_delay_2_halfcycles_floor++;
884 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
885 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
886 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
887 || (info->populated_ranks[1][0][0]
888 && info->populated_ranks[1][1][0]))
889 info->max_slots_used_in_channel = 2;
890 else
891 info->max_slots_used_in_channel = 1;
892 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200893 MCHBAR32(0x244 + (channel << 10)) =
894 ((info->revision < 8) ? 1 : 0x200) |
895 ((2 - info->max_slots_used_in_channel) << 17) |
896 (channel << 21) |
897 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100898 if (info->max_slots_used_in_channel == 1) {
899 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
900 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
901 } else {
902 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 */
903 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
904 || (count_ranks_in_channel(info, 1) ==
905 2)) ? 2 : 3;
906 }
907 for (channel = 0; channel < NUM_CHANNELS; channel++) {
908 int max_of_unk;
909 int min_of_unk_2;
910
911 int i, count;
912 int sum;
913
914 if (!info->populated_ranks_mask[channel])
915 continue;
916
917 max_of_unk = 0;
918 min_of_unk_2 = 32767;
919
920 sum = 0;
921 count = 0;
922 for (i = 0; i < 3; i++) {
923 int unk1;
924 if (info->revision < 8)
925 unk1 =
926 u8_FFFD1891[0][channel][info->
927 clock_speed_index]
928 [i];
929 else if (!
930 (info->revision >= 0x10
931 || info->revision_flag_1))
932 unk1 =
933 u8_FFFD1891[1][channel][info->
934 clock_speed_index]
935 [i];
936 else
937 unk1 = 0;
938 for (slot = 0; slot < NUM_SLOTS; slot++)
939 for (rank = 0; rank < NUM_RANKS; rank++) {
940 int a = 0;
941 int b = 0;
942
943 if (!info->
944 populated_ranks[channel][slot]
945 [rank])
946 continue;
947 if (extended_silicon_revision == 4
948 && (info->
949 populated_ranks_mask[channel] &
950 5) != 5) {
951 if ((info->
952 spd[channel][slot]
953 [REFERENCE_RAW_CARD_USED] &
954 0x1F) == 3) {
955 a = u16_ffd1178[0]
956 [info->
957 clock_speed_index];
958 b = u16_fe0eb8[0][info->
959 clock_speed_index];
960 } else
961 if ((info->
962 spd[channel][slot]
963 [REFERENCE_RAW_CARD_USED]
964 & 0x1F) == 5) {
965 a = u16_ffd1178[1]
966 [info->
967 clock_speed_index];
968 b = u16_fe0eb8[1][info->
969 clock_speed_index];
970 }
971 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100972 min_of_unk_2 = MIN(min_of_unk_2, a);
973 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100974 if (rank == 0) {
975 sum += a;
976 count++;
977 }
978 {
979 int t;
980 t = b +
981 u8_FFFD0EF8[channel]
982 [extended_silicon_revision]
983 [info->
984 mode4030[channel]][info->
985 clock_speed_index];
986 if (unk1 >= t)
987 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100988 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100989 unk1 - t);
990 }
991 }
992 {
993 int t =
994 u8_FFFD17E0[channel]
995 [extended_silicon_revision][info->
996 mode4030
997 [channel]]
998 [info->clock_speed_index] + min_of_unk_2;
999 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001000 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001001 }
1002 }
1003
Jacob Garber64fb4a32019-06-10 17:29:18 -06001004 if (count == 0)
1005 die("No memory ranks found for channel %u\n", channel);
1006
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001007 info->avg4044[channel] = sum / count;
1008 info->max4048[channel] = max_of_unk;
1009 }
1010}
1011
1012static void jedec_read(struct raminfo *info,
1013 int channel, int slot, int rank,
1014 int total_rank, u8 addr3, unsigned int value)
1015{
1016 /* Handle mirrored mapping. */
1017 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001018 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1019 ((addr3 >> 1) & 0x10);
1020 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1021 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022
1023 /* Handle mirrored mapping. */
1024 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1025 value =
1026 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1027 << 1);
1028
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001029 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001030
Felix Held04be2dd2018-07-29 04:53:22 +02001031 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1032 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001033
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001034 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001035}
1036
1037enum {
1038 MR1_RZQ12 = 512,
1039 MR1_RZQ2 = 64,
1040 MR1_RZQ4 = 4,
1041 MR1_ODS34OHM = 2
1042};
1043
1044enum {
1045 MR0_BT_INTERLEAVED = 8,
1046 MR0_DLL_RESET_ON = 256
1047};
1048
1049enum {
1050 MR2_RTT_WR_DISABLED = 0,
1051 MR2_RZQ2 = 1 << 10
1052};
1053
1054static void jedec_init(struct raminfo *info)
1055{
1056 int write_recovery;
1057 int channel, slot, rank;
1058 int total_rank;
1059 int dll_on;
1060 int self_refresh_temperature;
1061 int auto_self_refresh;
1062
1063 auto_self_refresh = 1;
1064 self_refresh_temperature = 1;
1065 if (info->board_lane_delay[3] <= 10) {
1066 if (info->board_lane_delay[3] <= 8)
1067 write_recovery = info->board_lane_delay[3] - 4;
1068 else
1069 write_recovery = 5;
1070 } else {
1071 write_recovery = 6;
1072 }
1073 FOR_POPULATED_RANKS {
1074 auto_self_refresh &=
1075 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1076 self_refresh_temperature &=
1077 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1078 }
1079 if (auto_self_refresh == 1)
1080 self_refresh_temperature = 0;
1081
1082 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1083 || (info->populated_ranks[0][0][0]
1084 && info->populated_ranks[0][1][0])
1085 || (info->populated_ranks[1][0][0]
1086 && info->populated_ranks[1][1][0]));
1087
1088 total_rank = 0;
1089
1090 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1091 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1092 int rzq_reg58e;
1093
1094 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1095 rzq_reg58e = 64;
1096 rtt = MR1_RZQ2;
1097 if (info->clock_speed_index != 0) {
1098 rzq_reg58e = 4;
1099 if (info->populated_ranks_mask[channel] == 3)
1100 rtt = MR1_RZQ4;
1101 }
1102 } else {
1103 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1104 rtt = MR1_RZQ12;
1105 rzq_reg58e = 64;
1106 rtt_wr = MR2_RZQ2;
1107 } else {
1108 rzq_reg58e = 4;
1109 rtt = MR1_RZQ4;
1110 }
1111 }
1112
Felix Held04be2dd2018-07-29 04:53:22 +02001113 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1114 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1115 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1116 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1117 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001118
1119 for (slot = 0; slot < NUM_SLOTS; slot++)
1120 for (rank = 0; rank < NUM_RANKS; rank++)
1121 if (info->populated_ranks[channel][slot][rank]) {
1122 jedec_read(info, channel, slot, rank,
1123 total_rank, 0x28,
1124 rtt_wr | (info->
1125 clock_speed_index
1126 << 3)
1127 | (auto_self_refresh << 6) |
1128 (self_refresh_temperature <<
1129 7));
1130 jedec_read(info, channel, slot, rank,
1131 total_rank, 0x38, 0);
1132 jedec_read(info, channel, slot, rank,
1133 total_rank, 0x18,
1134 rtt | MR1_ODS34OHM);
1135 jedec_read(info, channel, slot, rank,
1136 total_rank, 6,
1137 (dll_on << 12) |
1138 (write_recovery << 9)
1139 | ((info->cas_latency - 4) <<
1140 4) | MR0_BT_INTERLEAVED |
1141 MR0_DLL_RESET_ON);
1142 total_rank++;
1143 }
1144 }
1145}
1146
1147static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1148{
Martin Roth468d02c2019-10-23 21:44:42 -06001149 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001150 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1151 unsigned int channel_0_non_interleaved;
1152
1153 FOR_ALL_RANKS {
1154 if (info->populated_ranks[channel][slot][rank]) {
1155 total_mb[channel] +=
1156 pre_jedec ? 256 : (256 << info->
1157 density[channel][slot] >> info->
1158 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001159 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1160 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1161 (info->is_x16_module[channel][slot] |
1162 ((info->density[channel][slot] + 1) << 1))) |
1163 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001164 }
Felix Held04be2dd2018-07-29 04:53:22 +02001165 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1166 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 }
1168
1169 info->total_memory_mb = total_mb[0] + total_mb[1];
1170
1171 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001172 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001173 info->non_interleaved_part_mb =
1174 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1175 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001176 MCHBAR32(0x100) = channel_0_non_interleaved |
1177 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001178 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001179 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001180}
1181
1182static void program_board_delay(struct raminfo *info)
1183{
1184 int cas_latency_shift;
1185 int some_delay_ns;
1186 int some_delay_3_half_cycles;
1187
Martin Roth468d02c2019-10-23 21:44:42 -06001188 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189 int high_multiplier;
1190 int lane_3_delay;
1191 int cas_latency_derived;
1192
1193 high_multiplier = 0;
1194 some_delay_ns = 200;
1195 some_delay_3_half_cycles = 4;
1196 cas_latency_shift = info->silicon_revision == 0
1197 || info->silicon_revision == 1 ? 1 : 0;
1198 if (info->revision < 8) {
1199 some_delay_ns = 600;
1200 cas_latency_shift = 0;
1201 }
1202 {
1203 int speed_bit;
1204 speed_bit =
1205 ((info->clock_speed_index > 1
1206 || (info->silicon_revision != 2
1207 && info->silicon_revision != 3))) ^ (info->revision >=
1208 0x10);
1209 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1210 3, 1);
1211 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1212 3, 1);
1213 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1214 && (info->silicon_revision == 2
1215 || info->silicon_revision == 3))
1216 rmw_1d0(0x116, 5, 2, 4, 1);
1217 }
Felix Held04be2dd2018-07-29 04:53:22 +02001218 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1219 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001220
Felix Held04be2dd2018-07-29 04:53:22 +02001221 MCHBAR8(0x124) = info->board_lane_delay[4] +
1222 ((frequency_01(info) + 999) / 1000);
1223 MCHBAR16(0x125) = 0x1360;
1224 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001225 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001226 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001227 high_multiplier = 1;
1228 some_delay_2_half_cycles = ps_to_halfcycles(info,
1229 ((3 *
1230 fsbcycle_ps(info))
1231 >> 1) +
1232 (halfcycle_ps(info)
1233 *
1234 reg178_min[info->
1235 clock_speed_index]
1236 >> 6)
1237 +
1238 4 *
1239 halfcycle_ps(info)
1240 + 2230);
1241 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001242 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001243 (frequency_11(info) * 2) * (28 -
1244 some_delay_2_half_cycles) /
1245 (frequency_11(info) * 2 -
1246 4 * (info->fsb_frequency))) >> 3, 7);
1247 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001248 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001249 some_delay_3_half_cycles = 3;
1250 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001251 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1252 MCHBAR32(0x224 + (channel << 10)) =
1253 (info->max_slots_used_in_channel - 1) |
1254 ((info->cas_latency - 5 - info->clock_speed_index)
1255 << 21) | ((info->max_slots_used_in_channel +
1256 info->cas_latency - cas_latency_shift - 4) << 16) |
1257 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1258 ((info->cas_latency - info->clock_speed_index +
1259 info->max_slots_used_in_channel - 6) << 8);
1260 MCHBAR32(0x228 + (channel << 10)) =
1261 info->max_slots_used_in_channel;
1262 MCHBAR8(0x239 + (channel << 10)) = 32;
1263 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1264 (some_delay_3_half_cycles << 25) | 0x840000;
1265 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1266 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1267 MCHBAR32(0x24c + (channel << 10)) =
1268 ((!!info->clock_speed_index) << 17) |
1269 (((2 + info->clock_speed_index -
1270 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001271
Felix Held04be2dd2018-07-29 04:53:22 +02001272 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1273 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1274 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001275
1276 write_500(info, channel,
1277 ((!info->populated_ranks[channel][1][1])
1278 | (!info->populated_ranks[channel][1][0] << 1)
1279 | (!info->populated_ranks[channel][0][1] << 2)
1280 | (!info->populated_ranks[channel][0][0] << 3)),
1281 0x4c9, 4, 1);
1282 }
1283
Felix Held22ca8cb2018-07-29 05:09:44 +02001284 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001285 {
1286 u8 freq_divisor = 2;
1287 if (info->fsb_frequency == frequency_11(info))
1288 freq_divisor = 3;
1289 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1290 freq_divisor = 1;
1291 else
1292 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001293 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294 }
1295
1296 if (info->board_lane_delay[3] <= 10) {
1297 if (info->board_lane_delay[3] <= 8)
1298 lane_3_delay = info->board_lane_delay[3];
1299 else
1300 lane_3_delay = 10;
1301 } else {
1302 lane_3_delay = 12;
1303 }
1304 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1305 if (info->clock_speed_index > 1)
1306 cas_latency_derived++;
1307 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001308 MCHBAR32(0x240 + (channel << 10)) =
1309 ((info->clock_speed_index == 0) * 0x11000) |
1310 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1311 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001312 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1313 0x609, 6, 1);
1314 write_500(info, channel,
1315 info->clock_speed_index + 2 * info->cas_latency - 7,
1316 0x601, 6, 1);
1317
Felix Held04be2dd2018-07-29 04:53:22 +02001318 MCHBAR32(0x250 + (channel << 10)) =
1319 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1320 (info->board_lane_delay[7] << 2) |
1321 (info->board_lane_delay[4] << 16) |
1322 (info->board_lane_delay[1] << 25) |
1323 (info->board_lane_delay[1] << 29) | 1;
1324 MCHBAR32(0x254 + (channel << 10)) =
1325 (info->board_lane_delay[1] >> 3) |
1326 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1327 0x80 | (info->board_lane_delay[6] << 1) |
1328 (info->board_lane_delay[2] << 28) |
1329 (cas_latency_derived << 16) | 0x4700000;
1330 MCHBAR32(0x258 + (channel << 10)) =
1331 ((info->board_lane_delay[5] + info->clock_speed_index +
1332 9) << 12) | ((info->clock_speed_index -
1333 info->cas_latency + 12) << 8) |
1334 (info->board_lane_delay[2] << 17) |
1335 (info->board_lane_delay[4] << 24) | 0x47;
1336 MCHBAR32(0x25c + (channel << 10)) =
1337 (info->board_lane_delay[1] << 1) |
1338 (info->board_lane_delay[0] << 8) | 0x1da50000;
1339 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1340 MCHBAR8(0x5f8 + (channel << 10)) =
1341 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001342 }
1343
1344 program_modules_memory_map(info, 1);
1345
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001346 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001347 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1348 MCHBAR16_OR(0x612, 0x100);
1349 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001350 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001351 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001352 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001353 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001354 }
1355}
1356
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001357#define DEFAULT_PCI_MMIO_SIZE 2048
1358#define HOST_BRIDGE PCI_DEVFN(0, 0)
1359
1360static unsigned int get_mmio_size(void)
1361{
1362 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001363 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001364
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001365 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001366 if (dev)
1367 cfg = dev->chip_info;
1368
1369 /* If this is zero, it just means devicetree.cb didn't set it */
1370 if (!cfg || cfg->pci_mmio_size == 0)
1371 return DEFAULT_PCI_MMIO_SIZE;
1372 else
1373 return cfg->pci_mmio_size;
1374}
1375
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001376#define BETTER_MEMORY_MAP 0
1377
1378static void program_total_memory_map(struct raminfo *info)
1379{
1380 unsigned int TOM, TOLUD, TOUUD;
1381 unsigned int quickpath_reserved;
1382 unsigned int REMAPbase;
1383 unsigned int uma_base_igd;
1384 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001385 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001386 int memory_remap;
1387 unsigned int memory_map[8];
1388 int i;
1389 unsigned int current_limit;
1390 unsigned int tseg_base;
1391 int uma_size_igd = 0, uma_size_gtt = 0;
1392
1393 memset(memory_map, 0, sizeof(memory_map));
1394
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001396 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001397 gav(t);
1398 const int uma_sizes_gtt[16] =
1399 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1400 /* Igd memory */
1401 const int uma_sizes_igd[16] = {
1402 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1403 256, 512
1404 };
1405
1406 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1407 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1408 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001409
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001410 mmio_size = get_mmio_size();
1411
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 TOM = info->total_memory_mb;
1413 if (TOM == 4096)
1414 TOM = 4032;
1415 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001416 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001417 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418 memory_remap = 0;
1419 if (TOUUD - TOLUD > 64) {
1420 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001421 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 TOUUD = TOUUD - TOLUD + 4096;
1423 }
1424 if (TOUUD > 4096)
1425 memory_map[2] = TOUUD | 1;
1426 quickpath_reserved = 0;
1427
Jacob Garber975a7e32019-06-10 16:32:47 -06001428 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429
Jacob Garber975a7e32019-06-10 16:32:47 -06001430 gav(t);
1431
1432 if (t & 0x800) {
1433 u32 shift = t >> 20;
1434 if (shift == 0)
1435 die("Quickpath value is 0\n");
1436 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001438
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439 if (memory_remap)
1440 TOUUD -= quickpath_reserved;
1441
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442 uma_base_igd = TOLUD - uma_size_igd;
1443 uma_base_gtt = uma_base_igd - uma_size_gtt;
1444 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1445 if (!memory_remap)
1446 tseg_base -= quickpath_reserved;
1447 tseg_base = ALIGN_DOWN(tseg_base, 8);
1448
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001449 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1450 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001452 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1453 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001455 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456
1457 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1459 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001461 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462
1463 current_limit = 0;
1464 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1465 memory_map[1] = 4096;
1466 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001467 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001468 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1470 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001471 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472 }
1473}
1474
1475static void collect_system_info(struct raminfo *info)
1476{
1477 u32 capid0[3];
1478 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001479 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480
1481 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001482 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1483 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001484
1485 if (!info->heci_bar)
1486 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001487 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 if (!info->memory_reserved_for_heci_mb) {
1489 /* Wait for ME to be ready */
1490 intel_early_me_init();
1491 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1492 }
1493
1494 for (i = 0; i < 3; i++)
1495 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001496 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1497 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1499
1500 if ((capid0[1] >> 11) & 1)
1501 info->uma_enabled = 0;
1502 else
1503 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001504 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001505 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1506 info->silicon_revision = 0;
1507
1508 if (capid0[2] & 2) {
1509 info->silicon_revision = 0;
1510 info->max_supported_clock_speed_index = 2;
1511 for (channel = 0; channel < NUM_CHANNELS; channel++)
1512 if (info->populated_ranks[channel][0][0]
1513 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1514 3) {
1515 info->silicon_revision = 2;
1516 info->max_supported_clock_speed_index = 1;
1517 }
1518 } else {
1519 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1520 case 1:
1521 case 2:
1522 info->silicon_revision = 3;
1523 break;
1524 case 3:
1525 info->silicon_revision = 0;
1526 break;
1527 case 0:
1528 info->silicon_revision = 2;
1529 break;
1530 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001531 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001532 case 0x40:
1533 info->silicon_revision = 0;
1534 break;
1535 case 0x48:
1536 info->silicon_revision = 1;
1537 break;
1538 }
1539 }
1540}
1541
1542static void write_training_data(struct raminfo *info)
1543{
1544 int tm, channel, slot, rank, lane;
1545 if (info->revision < 8)
1546 return;
1547
1548 for (tm = 0; tm < 4; tm++)
1549 for (channel = 0; channel < NUM_CHANNELS; channel++)
1550 for (slot = 0; slot < NUM_SLOTS; slot++)
1551 for (rank = 0; rank < NUM_RANKS; rank++)
1552 for (lane = 0; lane < 9; lane++)
1553 write_500(info, channel,
1554 info->
1555 cached_training->
1556 lane_timings[tm]
1557 [channel][slot][rank]
1558 [lane],
1559 get_timing_register_addr
1560 (lane, tm, slot,
1561 rank), 9, 0);
1562 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1563 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1564}
1565
1566static void dump_timings(struct raminfo *info)
1567{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001569 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001571 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572 slot, rank);
1573 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001574 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001576 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577 read_500(info, channel,
1578 get_timing_register_addr
1579 (lane, i, slot, rank),
1580 9),
1581 info->training.
1582 lane_timings[i][channel][slot][rank]
1583 [lane]);
1584 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001585 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586 }
1587 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001588 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001590 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001591 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592}
1593
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001594/* Read timings and other registers that need to be restored verbatim and
1595 put them to CBMEM.
1596 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597static void save_timings(struct raminfo *info)
1598{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 int channel, slot, rank, lane, i;
1601
1602 train = info->training;
1603 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1604 for (i = 0; i < 4; i++)
1605 train.lane_timings[i][channel][slot][rank][lane] =
1606 read_500(info, channel,
1607 get_timing_register_addr(lane, i, slot,
1608 rank), 9);
1609 train.reg_178 = read_1d0(0x178, 7);
1610 train.reg_10b = read_1d0(0x10b, 6);
1611
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1613 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001614 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001615 train.reg274265[channel][0] = reg32 >> 16;
1616 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001617 train.reg274265[channel][2] =
1618 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001619 }
Felix Held04be2dd2018-07-29 04:53:22 +02001620 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1621 train.reg_6dc = MCHBAR32(0x6dc);
1622 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001623
Arthur Heymansb3282092019-04-14 17:53:28 +02001624 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1625 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001626
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001627 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001628 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1629 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001630}
1631
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001632static const struct ram_training *get_cached_training(void)
1633{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001634 struct region_device rdev;
1635 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1636 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001638 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640
1641/* FIXME: add timeout. */
1642static void wait_heci_ready(void)
1643{
Felix Held04be2dd2018-07-29 04:53:22 +02001644 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1645 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001646 write32((DEFAULT_HECIBAR + 0x4),
1647 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648}
1649
1650/* FIXME: add timeout. */
1651static void wait_heci_cb_avail(int len)
1652{
1653 union {
1654 struct mei_csr csr;
1655 u32 raw;
1656 } csr;
1657
Felix Held22ca8cb2018-07-29 05:09:44 +02001658 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1659 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001660
1661 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001662 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663 while (len >
1664 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001665 csr.csr.buffer_read_ptr))
1666 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667}
1668
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001669static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670{
1671 int len = (head->length + 3) / 4;
1672 int i;
1673
1674 wait_heci_cb_avail(len + 1);
1675
1676 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001677 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001681 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1682 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001683}
1684
1685static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001686send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001687{
1688 struct mei_header head;
1689 int maxlen;
1690
1691 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001692 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001693
1694 while (len) {
1695 int cur = len;
1696 if (cur > maxlen) {
1697 cur = maxlen;
1698 head.is_complete = 0;
1699 } else
1700 head.is_complete = 1;
1701 head.length = cur;
1702 head.reserved = 0;
1703 head.client_address = clientaddress;
1704 head.host_address = hostaddress;
1705 send_heci_packet(&head, (u32 *) msg);
1706 len -= cur;
1707 msg += cur;
1708 }
1709}
1710
1711/* FIXME: Add timeout. */
1712static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001713recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1714 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001715{
1716 union {
1717 struct mei_csr csr;
1718 u32 raw;
1719 } csr;
1720 int i = 0;
1721
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001722 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001723 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001724 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725 }
Felix Held04be2dd2018-07-29 04:53:22 +02001726 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1727 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001728 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 write32(DEFAULT_HECIBAR + 0x4,
1731 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 *packet_size = 0;
1733 return 0;
1734 }
1735 if (head->length + 4 > 4 * csr.csr.buffer_depth
1736 || head->length > *packet_size) {
1737 *packet_size = 0;
1738 return -1;
1739 }
1740
1741 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001742 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001743 while (((head->length + 3) >> 2) >
1744 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1745 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746
1747 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001748 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001749 *packet_size = head->length;
1750 if (!csr.csr.ready)
1751 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001752 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001753 return 0;
1754}
1755
1756/* FIXME: Add timeout. */
1757static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001758recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759{
1760 struct mei_header head;
1761 int current_position;
1762
1763 current_position = 0;
1764 while (1) {
1765 u32 current_size;
1766 current_size = *message_size - current_position;
1767 if (recv_heci_packet
1768 (info, &head, message + (current_position >> 2),
1769 &current_size) == -1)
1770 break;
1771 if (!current_size)
1772 break;
1773 current_position += current_size;
1774 if (head.is_complete) {
1775 *message_size = current_position;
1776 return 0;
1777 }
1778
1779 if (current_position >= *message_size)
1780 break;
1781 }
1782 *message_size = 0;
1783 return -1;
1784}
1785
1786static void send_heci_uma_message(struct raminfo *info)
1787{
1788 struct uma_reply {
1789 u8 group_id;
1790 u8 command;
1791 u8 reserved;
1792 u8 result;
1793 u8 field2;
1794 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001795 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001796 struct uma_message {
1797 u8 group_id;
1798 u8 cmd;
1799 u8 reserved;
1800 u8 result;
1801 u32 c2;
1802 u64 heci_uma_addr;
1803 u32 memory_reserved_for_heci_mb;
1804 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001805 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806 0, MKHI_SET_UMA, 0, 0,
1807 0x82,
1808 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1809 u32 reply_size;
1810
1811 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1812
1813 reply_size = sizeof(reply);
1814 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1815 return;
1816
1817 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1818 die("HECI init failed\n");
1819}
1820
1821static void setup_heci_uma(struct raminfo *info)
1822{
1823 u32 reg44;
1824
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001825 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001826 info->memory_reserved_for_heci_mb = 0;
1827 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001828 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001829 return;
1830
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001831 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1833 info->heci_uma_addr =
1834 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001835 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836 info->memory_reserved_for_heci_mb)) << 20;
1837
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001838 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001840 write32(DEFAULT_DMIBAR + 0x14,
1841 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1842 write32(DEFAULT_RCBA + 0x14,
1843 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1844 write32(DEFAULT_DMIBAR + 0x20,
1845 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1846 write32(DEFAULT_RCBA + 0x20,
1847 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1848 write32(DEFAULT_DMIBAR + 0x2c,
1849 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1850 write32(DEFAULT_RCBA + 0x30,
1851 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1852 write32(DEFAULT_DMIBAR + 0x38,
1853 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1854 write32(DEFAULT_RCBA + 0x40,
1855 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001856
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001857 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1858 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001859 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1860 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1861 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001862 }
1863
Felix Held04be2dd2018-07-29 04:53:22 +02001864 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865
1866 send_heci_uma_message(info);
1867
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001868 pci_write_config32(HECIDEV, 0x10, 0x0);
1869 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001870
1871}
1872
1873static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1874{
1875 int ranks_in_channel;
1876 ranks_in_channel = info->populated_ranks[channel][0][0]
1877 + info->populated_ranks[channel][0][1]
1878 + info->populated_ranks[channel][1][0]
1879 + info->populated_ranks[channel][1][1];
1880
1881 /* empty channel */
1882 if (ranks_in_channel == 0)
1883 return 1;
1884
1885 if (ranks_in_channel != ranks)
1886 return 0;
1887 /* single slot */
1888 if (info->populated_ranks[channel][0][0] !=
1889 info->populated_ranks[channel][1][0])
1890 return 1;
1891 if (info->populated_ranks[channel][0][1] !=
1892 info->populated_ranks[channel][1][1])
1893 return 1;
1894 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1895 return 0;
1896 if (info->density[channel][0] != info->density[channel][1])
1897 return 0;
1898 return 1;
1899}
1900
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001901static void read_4090(struct raminfo *info)
1902{
1903 int i, channel, slot, rank, lane;
1904 for (i = 0; i < 2; i++)
1905 for (slot = 0; slot < NUM_SLOTS; slot++)
1906 for (rank = 0; rank < NUM_RANKS; rank++)
1907 for (lane = 0; lane < 9; lane++)
1908 info->training.
1909 lane_timings[0][i][slot][rank][lane]
1910 = 32;
1911
1912 for (i = 1; i < 4; i++)
1913 for (channel = 0; channel < NUM_CHANNELS; channel++)
1914 for (slot = 0; slot < NUM_SLOTS; slot++)
1915 for (rank = 0; rank < NUM_RANKS; rank++)
1916 for (lane = 0; lane < 9; lane++) {
1917 info->training.
1918 lane_timings[i][channel]
1919 [slot][rank][lane] =
1920 read_500(info, channel,
1921 get_timing_register_addr
1922 (lane, i, slot,
1923 rank), 9)
1924 + (i == 1) * 11; // !!!!
1925 }
1926
1927}
1928
1929static u32 get_etalon2(int flip, u32 addr)
1930{
1931 const u16 invmask[] = {
1932 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1933 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1934 };
1935 u32 ret;
1936 u32 comp4 = addr / 480;
1937 addr %= 480;
1938 u32 comp1 = addr & 0xf;
1939 u32 comp2 = (addr >> 4) & 1;
1940 u32 comp3 = addr >> 5;
1941
1942 if (comp4)
1943 ret = 0x1010101 << (comp4 - 1);
1944 else
1945 ret = 0;
1946 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1947 ret = ~ret;
1948
1949 return ret;
1950}
1951
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001952static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001953{
1954 msr_t msr = {.lo = 0, .hi = 0 };
1955
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001956 wrmsr(MTRR_PHYS_BASE(3), msr);
1957 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958}
1959
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001960static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001961{
1962 msr_t msr;
1963 msr.lo = base | MTRR_TYPE_WRPROT;
1964 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001965 wrmsr(MTRR_PHYS_BASE(3), msr);
1966 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967 & 0xffffffff);
1968 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001969 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970}
1971
1972static void flush_cache(u32 start, u32 size)
1973{
1974 u32 end;
1975 u32 addr;
1976
1977 end = start + (ALIGN_DOWN(size + 4096, 4096));
1978 for (addr = start; addr < end; addr += 64)
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001979 clflush((void *)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001980}
1981
1982static void clear_errors(void)
1983{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001984 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001985}
1986
1987static void write_testing(struct raminfo *info, int totalrank, int flip)
1988{
1989 int nwrites = 0;
1990 /* in 8-byte units. */
1991 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001992 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001993
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001994 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995 for (offset = 0; offset < 9 * 480; offset += 2) {
1996 write32(base + offset * 8, get_etalon2(flip, offset));
1997 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1998 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1999 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2000 nwrites += 4;
2001 if (nwrites >= 320) {
2002 clear_errors();
2003 nwrites = 0;
2004 }
2005 }
2006}
2007
2008static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2009{
2010 u8 failmask = 0;
2011 int i;
2012 int comp1, comp2, comp3;
2013 u32 failxor[2] = { 0, 0 };
2014
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002015 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002016
2017 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2018 for (comp1 = 0; comp1 < 4; comp1++)
2019 for (comp2 = 0; comp2 < 60; comp2++) {
2020 u32 re[4];
2021 u32 curroffset =
2022 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2023 read128((total_rank << 28) | (curroffset << 3),
2024 (u64 *) re);
2025 failxor[0] |=
2026 get_etalon2(flip, curroffset) ^ re[0];
2027 failxor[1] |=
2028 get_etalon2(flip, curroffset) ^ re[1];
2029 failxor[0] |=
2030 get_etalon2(flip, curroffset | 1) ^ re[2];
2031 failxor[1] |=
2032 get_etalon2(flip, curroffset | 1) ^ re[3];
2033 }
2034 for (i = 0; i < 8; i++)
2035 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2036 failmask |= 1 << i;
2037 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002038 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002039 flush_cache((total_rank << 28), 1728 * 5 * 4);
2040 return failmask;
2041}
2042
2043const u32 seed1[0x18] = {
2044 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2045 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2046 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2047 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2048 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2049 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2050};
2051
2052static u32 get_seed2(int a, int b)
2053{
2054 const u32 seed2[5] = {
2055 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2056 0x5b6db6db,
2057 };
2058 u32 r;
2059 r = seed2[(a + (a >= 10)) / 5];
2060 return b ? ~r : r;
2061}
2062
2063static int make_shift(int comp2, int comp5, int x)
2064{
2065 const u8 seed3[32] = {
2066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2067 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2068 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2069 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2070 };
2071
2072 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2073}
2074
2075static u32 get_etalon(int flip, u32 addr)
2076{
2077 u32 mask_byte = 0;
2078 int comp1 = (addr >> 1) & 1;
2079 int comp2 = (addr >> 3) & 0x1f;
2080 int comp3 = (addr >> 8) & 0xf;
2081 int comp4 = (addr >> 12) & 0xf;
2082 int comp5 = (addr >> 16) & 0x1f;
2083 u32 mask_bit = ~(0x10001 << comp3);
2084 u32 part1;
2085 u32 part2;
2086 int byte;
2087
2088 part2 =
2089 ((seed1[comp5] >>
2090 make_shift(comp2, comp5,
2091 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2092 part1 =
2093 ((seed1[comp5] >>
2094 make_shift(comp2, comp5,
2095 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2096
2097 for (byte = 0; byte < 4; byte++)
2098 if ((get_seed2(comp5, comp4) >>
2099 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2100 mask_byte |= 0xff << (8 * byte);
2101
2102 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2103 (comp3 + 16));
2104}
2105
2106static void
2107write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2108 char flip)
2109{
2110 int i;
2111 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002112 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2113 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002114}
2115
2116static u8
2117check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2118 char flip)
2119{
2120 u8 failmask = 0;
2121 u32 failxor[2];
2122 int i;
2123 int comp1, comp2, comp3;
2124
2125 failxor[0] = 0;
2126 failxor[1] = 0;
2127
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002128 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002129 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2130 for (comp1 = 0; comp1 < 16; comp1++)
2131 for (comp2 = 0; comp2 < 64; comp2++) {
2132 u32 addr =
2133 (totalrank << 28) | (region << 25) | (block
2134 << 16)
2135 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2136 2);
2137 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002138 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002139 }
2140 for (i = 0; i < 8; i++)
2141 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2142 failmask |= 1 << i;
2143 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002144 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002145 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2146 return failmask;
2147}
2148
2149static int check_bounded(unsigned short *vals, u16 bound)
2150{
2151 int i;
2152
2153 for (i = 0; i < 8; i++)
2154 if (vals[i] < bound)
2155 return 0;
2156 return 1;
2157}
2158
2159enum state {
2160 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2161};
2162
2163static int validate_state(enum state *in)
2164{
2165 int i;
2166 for (i = 0; i < 8; i++)
2167 if (in[i] != COMPLETE)
2168 return 0;
2169 return 1;
2170}
2171
2172static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002173do_fsm(enum state *state, u16 *counter,
2174 u8 fail_mask, int margin, int uplimit,
2175 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002176{
2177 int lane;
2178
2179 for (lane = 0; lane < 8; lane++) {
2180 int is_fail = (fail_mask >> lane) & 1;
2181 switch (state[lane]) {
2182 case BEFORE_USABLE:
2183 if (!is_fail) {
2184 counter[lane] = 1;
2185 state[lane] = AT_USABLE;
2186 break;
2187 }
2188 counter[lane] = 0;
2189 state[lane] = BEFORE_USABLE;
2190 break;
2191 case AT_USABLE:
2192 if (!is_fail) {
2193 ++counter[lane];
2194 if (counter[lane] >= margin) {
2195 state[lane] = AT_MARGIN;
2196 res_low[lane] = val - margin + 1;
2197 break;
2198 }
2199 state[lane] = 1;
2200 break;
2201 }
2202 counter[lane] = 0;
2203 state[lane] = BEFORE_USABLE;
2204 break;
2205 case AT_MARGIN:
2206 if (is_fail) {
2207 state[lane] = COMPLETE;
2208 res_high[lane] = val - 1;
2209 } else {
2210 counter[lane]++;
2211 state[lane] = AT_MARGIN;
2212 if (val == uplimit) {
2213 state[lane] = COMPLETE;
2214 res_high[lane] = uplimit;
2215 }
2216 }
2217 break;
2218 case COMPLETE:
2219 break;
2220 }
2221 }
2222}
2223
2224static void
2225train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2226 u8 total_rank, u8 reg_178, int first_run, int niter,
2227 timing_bounds_t * timings)
2228{
2229 int lane;
2230 enum state state[8];
2231 u16 count[8];
2232 u8 lower_usable[8];
2233 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002234 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002235 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002236 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002237
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002238 for (i = 0; i < 8; i++)
2239 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002240
2241 if (!first_run) {
2242 int is_all_ok = 1;
2243 for (lane = 0; lane < 8; lane++)
2244 if (timings[reg_178][channel][slot][rank][lane].
2245 smallest ==
2246 timings[reg_178][channel][slot][rank][lane].
2247 largest) {
2248 timings[reg_178][channel][slot][rank][lane].
2249 smallest = 0;
2250 timings[reg_178][channel][slot][rank][lane].
2251 largest = 0;
2252 is_all_ok = 0;
2253 }
2254 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002255 for (i = 0; i < 8; i++)
2256 state[i] = COMPLETE;
2257 }
2258 }
2259
2260 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2261 u8 failmask = 0;
2262 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2263 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2264 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002265 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002266 do_fsm(state, count, failmask, 5, 47, lower_usable,
2267 upper_usable, reg1b3);
2268 }
2269
2270 if (reg1b3) {
2271 write_1d0(0, 0x1b3, 6, 1);
2272 write_1d0(0, 0x1a3, 6, 1);
2273 for (lane = 0; lane < 8; lane++) {
2274 if (state[lane] == COMPLETE) {
2275 timings[reg_178][channel][slot][rank][lane].
2276 smallest =
2277 lower_usable[lane] +
2278 (info->training.
2279 lane_timings[0][channel][slot][rank][lane]
2280 & 0x3F) - 32;
2281 timings[reg_178][channel][slot][rank][lane].
2282 largest =
2283 upper_usable[lane] +
2284 (info->training.
2285 lane_timings[0][channel][slot][rank][lane]
2286 & 0x3F) - 32;
2287 }
2288 }
2289 }
2290
2291 if (!first_run) {
2292 for (lane = 0; lane < 8; lane++)
2293 if (state[lane] == COMPLETE) {
2294 write_500(info, channel,
2295 timings[reg_178][channel][slot][rank]
2296 [lane].smallest,
2297 get_timing_register_addr(lane, 0,
2298 slot, rank),
2299 9, 1);
2300 write_500(info, channel,
2301 timings[reg_178][channel][slot][rank]
2302 [lane].smallest +
2303 info->training.
2304 lane_timings[1][channel][slot][rank]
2305 [lane]
2306 -
2307 info->training.
2308 lane_timings[0][channel][slot][rank]
2309 [lane], get_timing_register_addr(lane,
2310 1,
2311 slot,
2312 rank),
2313 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002314 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002315 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002316 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002317
2318 do {
2319 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002320 for (i = 0; i < niter; i++) {
2321 if (failmask == 0xFF)
2322 break;
2323 failmask |=
2324 check_testing_type2(info, total_rank, 2, i,
2325 0);
2326 failmask |=
2327 check_testing_type2(info, total_rank, 3, i,
2328 1);
2329 }
Felix Held04be2dd2018-07-29 04:53:22 +02002330 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002331 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002332 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002333 if ((1 << lane) & failmask) {
2334 if (timings[reg_178][channel]
2335 [slot][rank][lane].
2336 largest <=
2337 timings[reg_178][channel]
2338 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002339 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002340 [lane] = -1;
2341 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002342 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002343 [lane] = 0;
2344 timings[reg_178]
2345 [channel][slot]
2346 [rank][lane].
2347 smallest++;
2348 write_500(info, channel,
2349 timings
2350 [reg_178]
2351 [channel]
2352 [slot][rank]
2353 [lane].
2354 smallest,
2355 get_timing_register_addr
2356 (lane, 0,
2357 slot, rank),
2358 9, 1);
2359 write_500(info, channel,
2360 timings
2361 [reg_178]
2362 [channel]
2363 [slot][rank]
2364 [lane].
2365 smallest +
2366 info->
2367 training.
2368 lane_timings
2369 [1][channel]
2370 [slot][rank]
2371 [lane]
2372 -
2373 info->
2374 training.
2375 lane_timings
2376 [0][channel]
2377 [slot][rank]
2378 [lane],
2379 get_timing_register_addr
2380 (lane, 1,
2381 slot, rank),
2382 9, 1);
2383 }
2384 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002385 num_successfully_checked[lane]
2386 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002387 }
2388 }
Felix Held04be2dd2018-07-29 04:53:22 +02002389 while (!check_bounded(num_successfully_checked, 2))
2390 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002391
2392 for (lane = 0; lane < 8; lane++)
2393 if (state[lane] == COMPLETE) {
2394 write_500(info, channel,
2395 timings[reg_178][channel][slot][rank]
2396 [lane].largest,
2397 get_timing_register_addr(lane, 0,
2398 slot, rank),
2399 9, 1);
2400 write_500(info, channel,
2401 timings[reg_178][channel][slot][rank]
2402 [lane].largest +
2403 info->training.
2404 lane_timings[1][channel][slot][rank]
2405 [lane]
2406 -
2407 info->training.
2408 lane_timings[0][channel][slot][rank]
2409 [lane], get_timing_register_addr(lane,
2410 1,
2411 slot,
2412 rank),
2413 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002414 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002415 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002416 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002417
2418 do {
2419 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002420 for (i = 0; i < niter; i++) {
2421 if (failmask == 0xFF)
2422 break;
2423 failmask |=
2424 check_testing_type2(info, total_rank, 2, i,
2425 0);
2426 failmask |=
2427 check_testing_type2(info, total_rank, 3, i,
2428 1);
2429 }
2430
Felix Held04be2dd2018-07-29 04:53:22 +02002431 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002432 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002433 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434 if ((1 << lane) & failmask) {
2435 if (timings[reg_178][channel]
2436 [slot][rank][lane].
2437 largest <=
2438 timings[reg_178][channel]
2439 [slot][rank][lane].
2440 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002441 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002442 [lane] = -1;
2443 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002444 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002445 [lane] = 0;
2446 timings[reg_178]
2447 [channel][slot]
2448 [rank][lane].
2449 largest--;
2450 write_500(info, channel,
2451 timings
2452 [reg_178]
2453 [channel]
2454 [slot][rank]
2455 [lane].
2456 largest,
2457 get_timing_register_addr
2458 (lane, 0,
2459 slot, rank),
2460 9, 1);
2461 write_500(info, channel,
2462 timings
2463 [reg_178]
2464 [channel]
2465 [slot][rank]
2466 [lane].
2467 largest +
2468 info->
2469 training.
2470 lane_timings
2471 [1][channel]
2472 [slot][rank]
2473 [lane]
2474 -
2475 info->
2476 training.
2477 lane_timings
2478 [0][channel]
2479 [slot][rank]
2480 [lane],
2481 get_timing_register_addr
2482 (lane, 1,
2483 slot, rank),
2484 9, 1);
2485 }
2486 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002487 num_successfully_checked[lane]
2488 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002489 }
2490 }
2491 }
Felix Held04be2dd2018-07-29 04:53:22 +02002492 while (!check_bounded(num_successfully_checked, 3))
2493 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002494
2495 for (lane = 0; lane < 8; lane++) {
2496 write_500(info, channel,
2497 info->training.
2498 lane_timings[0][channel][slot][rank][lane],
2499 get_timing_register_addr(lane, 0, slot, rank),
2500 9, 1);
2501 write_500(info, channel,
2502 info->training.
2503 lane_timings[1][channel][slot][rank][lane],
2504 get_timing_register_addr(lane, 1, slot, rank),
2505 9, 1);
2506 if (timings[reg_178][channel][slot][rank][lane].
2507 largest <=
2508 timings[reg_178][channel][slot][rank][lane].
2509 smallest) {
2510 timings[reg_178][channel][slot][rank][lane].
2511 largest = 0;
2512 timings[reg_178][channel][slot][rank][lane].
2513 smallest = 0;
2514 }
2515 }
2516 }
2517}
2518
2519static void set_10b(struct raminfo *info, u8 val)
2520{
2521 int channel;
2522 int slot, rank;
2523 int lane;
2524
2525 if (read_1d0(0x10b, 6) == val)
2526 return;
2527
2528 write_1d0(val, 0x10b, 6, 1);
2529
2530 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2531 u16 reg_500;
2532 reg_500 = read_500(info, channel,
2533 get_timing_register_addr(lane, 0, slot,
2534 rank), 9);
2535 if (val == 1) {
2536 if (lut16[info->clock_speed_index] <= reg_500)
2537 reg_500 -= lut16[info->clock_speed_index];
2538 else
2539 reg_500 = 0;
2540 } else {
2541 reg_500 += lut16[info->clock_speed_index];
2542 }
2543 write_500(info, channel, reg_500,
2544 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2545 }
2546}
2547
2548static void set_ecc(int onoff)
2549{
2550 int channel;
2551 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2552 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002553 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002554 if (onoff)
2555 t |= 1;
2556 else
2557 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002558 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002559 }
2560}
2561
2562static void set_178(u8 val)
2563{
2564 if (val >= 31)
2565 val = val - 31;
2566 else
2567 val = 63 - val;
2568
2569 write_1d0(2 * val, 0x178, 7, 1);
2570}
2571
2572static void
2573write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2574 int type)
2575{
2576 int lane;
2577
2578 for (lane = 0; lane < 8; lane++)
2579 write_500(info, channel,
2580 info->training.
2581 lane_timings[type][channel][slot][rank][lane],
2582 get_timing_register_addr(lane, type, slot, rank), 9,
2583 0);
2584}
2585
2586static void
2587try_timing_offsets(struct raminfo *info, int channel,
2588 int slot, int rank, int totalrank)
2589{
2590 u16 count[8];
2591 enum state state[8];
2592 u8 lower_usable[8], upper_usable[8];
2593 int lane;
2594 int i;
2595 int flip = 1;
2596 int timing_offset;
2597
2598 for (i = 0; i < 8; i++)
2599 state[i] = BEFORE_USABLE;
2600
2601 memset(count, 0, sizeof(count));
2602
2603 for (lane = 0; lane < 8; lane++)
2604 write_500(info, channel,
2605 info->training.
2606 lane_timings[2][channel][slot][rank][lane] + 32,
2607 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2608
2609 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2610 timing_offset++) {
2611 u8 failmask;
2612 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2613 failmask = 0;
2614 for (i = 0; i < 2 && failmask != 0xff; i++) {
2615 flip = !flip;
2616 write_testing(info, totalrank, flip);
2617 failmask |= check_testing(info, totalrank, flip);
2618 }
2619 do_fsm(state, count, failmask, 10, 63, lower_usable,
2620 upper_usable, timing_offset);
2621 }
2622 write_1d0(0, 0x1bb, 6, 1);
2623 dump_timings(info);
2624 if (!validate_state(state))
2625 die("Couldn't discover DRAM timings (1)\n");
2626
2627 for (lane = 0; lane < 8; lane++) {
2628 u8 bias = 0;
2629
2630 if (info->silicon_revision) {
2631 int usable_length;
2632
2633 usable_length = upper_usable[lane] - lower_usable[lane];
2634 if (usable_length >= 20) {
2635 bias = usable_length / 2 - 10;
2636 if (bias >= 2)
2637 bias = 2;
2638 }
2639 }
2640 write_500(info, channel,
2641 info->training.
2642 lane_timings[2][channel][slot][rank][lane] +
2643 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2644 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2645 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2646 info->training.lane_timings[2][channel][slot][rank][lane] +
2647 lower_usable[lane];
2648 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2649 info->training.lane_timings[2][channel][slot][rank][lane] +
2650 upper_usable[lane];
2651 info->training.timing2_offset[channel][slot][rank][lane] =
2652 info->training.lane_timings[2][channel][slot][rank][lane];
2653 }
2654}
2655
2656static u8
2657choose_training(struct raminfo *info, int channel, int slot, int rank,
2658 int lane, timing_bounds_t * timings, u8 center_178)
2659{
2660 u16 central_weight;
2661 u16 side_weight;
2662 unsigned int sum = 0, count = 0;
2663 u8 span;
2664 u8 lower_margin, upper_margin;
2665 u8 reg_178;
2666 u8 result;
2667
2668 span = 12;
2669 central_weight = 20;
2670 side_weight = 20;
2671 if (info->silicon_revision == 1 && channel == 1) {
2672 central_weight = 5;
2673 side_weight = 20;
2674 if ((info->
2675 populated_ranks_mask[1] ^ (info->
2676 populated_ranks_mask[1] >> 2)) &
2677 1)
2678 span = 18;
2679 }
2680 if ((info->populated_ranks_mask[0] & 5) == 5) {
2681 central_weight = 20;
2682 side_weight = 20;
2683 }
2684 if (info->clock_speed_index >= 2
2685 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2686 if (info->silicon_revision == 1) {
2687 switch (channel) {
2688 case 0:
2689 if (lane == 1) {
2690 central_weight = 10;
2691 side_weight = 20;
2692 }
2693 break;
2694 case 1:
2695 if (lane == 6) {
2696 side_weight = 5;
2697 central_weight = 20;
2698 }
2699 break;
2700 }
2701 }
2702 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2703 side_weight = 5;
2704 central_weight = 20;
2705 }
2706 }
2707 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2708 reg_178 += span) {
2709 u8 smallest;
2710 u8 largest;
2711 largest = timings[reg_178][channel][slot][rank][lane].largest;
2712 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2713 if (largest - smallest + 1 >= 5) {
2714 unsigned int weight;
2715 if (reg_178 == center_178)
2716 weight = central_weight;
2717 else
2718 weight = side_weight;
2719 sum += weight * (largest + smallest);
2720 count += weight;
2721 }
2722 }
2723 dump_timings(info);
2724 if (count == 0)
2725 die("Couldn't discover DRAM timings (2)\n");
2726 result = sum / (2 * count);
2727 lower_margin =
2728 result - timings[center_178][channel][slot][rank][lane].smallest;
2729 upper_margin =
2730 timings[center_178][channel][slot][rank][lane].largest - result;
2731 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002732 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002733 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002734 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002735 return result;
2736}
2737
2738#define STANDARD_MIN_MARGIN 5
2739
2740static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2741{
2742 u16 margin[64];
2743 int lane, rank, slot, channel;
2744 u8 reg178;
2745 int count = 0, sum = 0;
2746
2747 for (reg178 = reg178_min[info->clock_speed_index];
2748 reg178 < reg178_max[info->clock_speed_index];
2749 reg178 += reg178_step[info->clock_speed_index]) {
2750 margin[reg178] = -1;
2751 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2752 int curmargin =
2753 timings[reg178][channel][slot][rank][lane].largest -
2754 timings[reg178][channel][slot][rank][lane].
2755 smallest + 1;
2756 if (curmargin < margin[reg178])
2757 margin[reg178] = curmargin;
2758 }
2759 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2760 u16 weight;
2761 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2762 sum += weight * reg178;
2763 count += weight;
2764 }
2765 }
2766 dump_timings(info);
2767 if (count == 0)
2768 die("Couldn't discover DRAM timings (3)\n");
2769
2770 u8 threshold;
2771
2772 for (threshold = 30; threshold >= 5; threshold--) {
2773 int usable_length = 0;
2774 int smallest_fount = 0;
2775 for (reg178 = reg178_min[info->clock_speed_index];
2776 reg178 < reg178_max[info->clock_speed_index];
2777 reg178 += reg178_step[info->clock_speed_index])
2778 if (margin[reg178] >= threshold) {
2779 usable_length +=
2780 reg178_step[info->clock_speed_index];
2781 info->training.reg178_largest =
2782 reg178 -
2783 2 * reg178_step[info->clock_speed_index];
2784
2785 if (!smallest_fount) {
2786 smallest_fount = 1;
2787 info->training.reg178_smallest =
2788 reg178 +
2789 reg178_step[info->
2790 clock_speed_index];
2791 }
2792 }
2793 if (usable_length >= 0x21)
2794 break;
2795 }
2796
2797 return sum / count;
2798}
2799
2800static int check_cached_sanity(struct raminfo *info)
2801{
2802 int lane;
2803 int slot, rank;
2804 int channel;
2805
2806 if (!info->cached_training)
2807 return 0;
2808
2809 for (channel = 0; channel < NUM_CHANNELS; channel++)
2810 for (slot = 0; slot < NUM_SLOTS; slot++)
2811 for (rank = 0; rank < NUM_RANKS; rank++)
2812 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2813 u16 cached_value, estimation_value;
2814 cached_value =
2815 info->cached_training->
2816 lane_timings[1][channel][slot][rank]
2817 [lane];
2818 if (cached_value >= 0x18
2819 && cached_value <= 0x1E7) {
2820 estimation_value =
2821 info->training.
2822 lane_timings[1][channel]
2823 [slot][rank][lane];
2824 if (estimation_value <
2825 cached_value - 24)
2826 return 0;
2827 if (estimation_value >
2828 cached_value + 24)
2829 return 0;
2830 }
2831 }
2832 return 1;
2833}
2834
2835static int try_cached_training(struct raminfo *info)
2836{
2837 u8 saved_243[2];
2838 u8 tm;
2839
2840 int channel, slot, rank, lane;
2841 int flip = 1;
2842 int i, j;
2843
2844 if (!check_cached_sanity(info))
2845 return 0;
2846
2847 info->training.reg178_center = info->cached_training->reg178_center;
2848 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2849 info->training.reg178_largest = info->cached_training->reg178_largest;
2850 memcpy(&info->training.timing_bounds,
2851 &info->cached_training->timing_bounds,
2852 sizeof(info->training.timing_bounds));
2853 memcpy(&info->training.timing_offset,
2854 &info->cached_training->timing_offset,
2855 sizeof(info->training.timing_offset));
2856
2857 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002858 saved_243[0] = MCHBAR8(0x243);
2859 saved_243[1] = MCHBAR8(0x643);
2860 MCHBAR8(0x243) = saved_243[0] | 2;
2861 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002862 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002863 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002864 if (read_1d0(0x10b, 6) & 1)
2865 set_10b(info, 0);
2866 for (tm = 0; tm < 2; tm++) {
2867 int totalrank;
2868
2869 set_178(tm ? info->cached_training->reg178_largest : info->
2870 cached_training->reg178_smallest);
2871
2872 totalrank = 0;
2873 /* Check timing ranges. With i == 0 we check smallest one and with
2874 i == 1 the largest bound. With j == 0 we check that on the bound
2875 it still works whereas with j == 1 we check that just outside of
2876 bound we fail.
2877 */
2878 FOR_POPULATED_RANKS_BACKWARDS {
2879 for (i = 0; i < 2; i++) {
2880 for (lane = 0; lane < 8; lane++) {
2881 write_500(info, channel,
2882 info->cached_training->
2883 timing2_bounds[channel][slot]
2884 [rank][lane][i],
2885 get_timing_register_addr(lane,
2886 3,
2887 slot,
2888 rank),
2889 9, 1);
2890
2891 if (!i)
2892 write_500(info, channel,
2893 info->
2894 cached_training->
2895 timing2_offset
2896 [channel][slot][rank]
2897 [lane],
2898 get_timing_register_addr
2899 (lane, 2, slot, rank),
2900 9, 1);
2901 write_500(info, channel,
2902 i ? info->cached_training->
2903 timing_bounds[tm][channel]
2904 [slot][rank][lane].
2905 largest : info->
2906 cached_training->
2907 timing_bounds[tm][channel]
2908 [slot][rank][lane].smallest,
2909 get_timing_register_addr(lane,
2910 0,
2911 slot,
2912 rank),
2913 9, 1);
2914 write_500(info, channel,
2915 info->cached_training->
2916 timing_offset[channel][slot]
2917 [rank][lane] +
2918 (i ? info->cached_training->
2919 timing_bounds[tm][channel]
2920 [slot][rank][lane].
2921 largest : info->
2922 cached_training->
2923 timing_bounds[tm][channel]
2924 [slot][rank][lane].
2925 smallest) - 64,
2926 get_timing_register_addr(lane,
2927 1,
2928 slot,
2929 rank),
2930 9, 1);
2931 }
2932 for (j = 0; j < 2; j++) {
2933 u8 failmask;
2934 u8 expected_failmask;
2935 char reg1b3;
2936
2937 reg1b3 = (j == 1) + 4;
2938 reg1b3 =
2939 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2940 write_1d0(reg1b3, 0x1bb, 6, 1);
2941 write_1d0(reg1b3, 0x1b3, 6, 1);
2942 write_1d0(reg1b3, 0x1a3, 6, 1);
2943
2944 flip = !flip;
2945 write_testing(info, totalrank, flip);
2946 failmask =
2947 check_testing(info, totalrank,
2948 flip);
2949 expected_failmask =
2950 j == 0 ? 0x00 : 0xff;
2951 if (failmask != expected_failmask)
2952 goto fail;
2953 }
2954 }
2955 totalrank++;
2956 }
2957 }
2958
2959 set_178(info->cached_training->reg178_center);
2960 if (info->use_ecc)
2961 set_ecc(1);
2962 write_training_data(info);
2963 write_1d0(0, 322, 3, 1);
2964 info->training = *info->cached_training;
2965
2966 write_1d0(0, 0x1bb, 6, 1);
2967 write_1d0(0, 0x1b3, 6, 1);
2968 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002969 MCHBAR8(0x243) = saved_243[0];
2970 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002971
2972 return 1;
2973
2974fail:
2975 FOR_POPULATED_RANKS {
2976 write_500_timings_type(info, channel, slot, rank, 1);
2977 write_500_timings_type(info, channel, slot, rank, 2);
2978 write_500_timings_type(info, channel, slot, rank, 3);
2979 }
2980
2981 write_1d0(0, 0x1bb, 6, 1);
2982 write_1d0(0, 0x1b3, 6, 1);
2983 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002984 MCHBAR8(0x243) = saved_243[0];
2985 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002986
2987 return 0;
2988}
2989
2990static void do_ram_training(struct raminfo *info)
2991{
2992 u8 saved_243[2];
2993 int totalrank = 0;
2994 u8 reg_178;
2995 int niter;
2996
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002997 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002998 int lane, rank, slot, channel;
2999 u8 reg178_center;
3000
3001 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003002 saved_243[0] = MCHBAR8(0x243);
3003 saved_243[1] = MCHBAR8(0x643);
3004 MCHBAR8(0x243) = saved_243[0] | 2;
3005 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003006 switch (info->clock_speed_index) {
3007 case 0:
3008 niter = 5;
3009 break;
3010 case 1:
3011 niter = 10;
3012 break;
3013 default:
3014 niter = 19;
3015 break;
3016 }
3017 set_ecc(0);
3018
3019 FOR_POPULATED_RANKS_BACKWARDS {
3020 int i;
3021
3022 write_500_timings_type(info, channel, slot, rank, 0);
3023
3024 write_testing(info, totalrank, 0);
3025 for (i = 0; i < niter; i++) {
3026 write_testing_type2(info, totalrank, 2, i, 0);
3027 write_testing_type2(info, totalrank, 3, i, 1);
3028 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003029 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003030 totalrank++;
3031 }
3032
3033 if (reg178_min[info->clock_speed_index] <
3034 reg178_max[info->clock_speed_index])
3035 memset(timings[reg178_min[info->clock_speed_index]], 0,
3036 sizeof(timings[0]) *
3037 (reg178_max[info->clock_speed_index] -
3038 reg178_min[info->clock_speed_index]));
3039 for (reg_178 = reg178_min[info->clock_speed_index];
3040 reg_178 < reg178_max[info->clock_speed_index];
3041 reg_178 += reg178_step[info->clock_speed_index]) {
3042 totalrank = 0;
3043 set_178(reg_178);
3044 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3045 for (slot = 0; slot < NUM_SLOTS; slot++)
3046 for (rank = 0; rank < NUM_RANKS; rank++) {
3047 memset(&timings[reg_178][channel][slot]
3048 [rank][0].smallest, 0, 16);
3049 if (info->
3050 populated_ranks[channel][slot]
3051 [rank]) {
3052 train_ram_at_178(info, channel,
3053 slot, rank,
3054 totalrank,
3055 reg_178, 1,
3056 niter,
3057 timings);
3058 totalrank++;
3059 }
3060 }
3061 }
3062
3063 reg178_center = choose_reg178(info, timings);
3064
3065 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3066 info->training.timing_bounds[0][channel][slot][rank][lane].
3067 smallest =
3068 timings[info->training.
3069 reg178_smallest][channel][slot][rank][lane].
3070 smallest;
3071 info->training.timing_bounds[0][channel][slot][rank][lane].
3072 largest =
3073 timings[info->training.
3074 reg178_smallest][channel][slot][rank][lane].largest;
3075 info->training.timing_bounds[1][channel][slot][rank][lane].
3076 smallest =
3077 timings[info->training.
3078 reg178_largest][channel][slot][rank][lane].smallest;
3079 info->training.timing_bounds[1][channel][slot][rank][lane].
3080 largest =
3081 timings[info->training.
3082 reg178_largest][channel][slot][rank][lane].largest;
3083 info->training.timing_offset[channel][slot][rank][lane] =
3084 info->training.lane_timings[1][channel][slot][rank][lane]
3085 -
3086 info->training.lane_timings[0][channel][slot][rank][lane] +
3087 64;
3088 }
3089
3090 if (info->silicon_revision == 1
3091 && (info->
3092 populated_ranks_mask[1] ^ (info->
3093 populated_ranks_mask[1] >> 2)) & 1) {
3094 int ranks_after_channel1;
3095
3096 totalrank = 0;
3097 for (reg_178 = reg178_center - 18;
3098 reg_178 <= reg178_center + 18; reg_178 += 18) {
3099 totalrank = 0;
3100 set_178(reg_178);
3101 for (slot = 0; slot < NUM_SLOTS; slot++)
3102 for (rank = 0; rank < NUM_RANKS; rank++) {
3103 if (info->
3104 populated_ranks[1][slot][rank]) {
3105 train_ram_at_178(info, 1, slot,
3106 rank,
3107 totalrank,
3108 reg_178, 0,
3109 niter,
3110 timings);
3111 totalrank++;
3112 }
3113 }
3114 }
3115 ranks_after_channel1 = totalrank;
3116
3117 for (reg_178 = reg178_center - 12;
3118 reg_178 <= reg178_center + 12; reg_178 += 12) {
3119 totalrank = ranks_after_channel1;
3120 set_178(reg_178);
3121 for (slot = 0; slot < NUM_SLOTS; slot++)
3122 for (rank = 0; rank < NUM_RANKS; rank++)
3123 if (info->
3124 populated_ranks[0][slot][rank]) {
3125 train_ram_at_178(info, 0, slot,
3126 rank,
3127 totalrank,
3128 reg_178, 0,
3129 niter,
3130 timings);
3131 totalrank++;
3132 }
3133
3134 }
3135 } else {
3136 for (reg_178 = reg178_center - 12;
3137 reg_178 <= reg178_center + 12; reg_178 += 12) {
3138 totalrank = 0;
3139 set_178(reg_178);
3140 FOR_POPULATED_RANKS_BACKWARDS {
3141 train_ram_at_178(info, channel, slot, rank,
3142 totalrank, reg_178, 0, niter,
3143 timings);
3144 totalrank++;
3145 }
3146 }
3147 }
3148
3149 set_178(reg178_center);
3150 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3151 u16 tm0;
3152
3153 tm0 =
3154 choose_training(info, channel, slot, rank, lane, timings,
3155 reg178_center);
3156 write_500(info, channel, tm0,
3157 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3158 write_500(info, channel,
3159 tm0 +
3160 info->training.
3161 lane_timings[1][channel][slot][rank][lane] -
3162 info->training.
3163 lane_timings[0][channel][slot][rank][lane],
3164 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3165 }
3166
3167 totalrank = 0;
3168 FOR_POPULATED_RANKS_BACKWARDS {
3169 try_timing_offsets(info, channel, slot, rank, totalrank);
3170 totalrank++;
3171 }
Felix Held04be2dd2018-07-29 04:53:22 +02003172 MCHBAR8(0x243) = saved_243[0];
3173 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003174 write_1d0(0, 0x142, 3, 1);
3175 info->training.reg178_center = reg178_center;
3176}
3177
3178static void ram_training(struct raminfo *info)
3179{
3180 u16 saved_fc4;
3181
Felix Held04be2dd2018-07-29 04:53:22 +02003182 saved_fc4 = MCHBAR16(0xfc4);
3183 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003184
3185 if (info->revision >= 8)
3186 read_4090(info);
3187
3188 if (!try_cached_training(info))
3189 do_ram_training(info);
3190 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3191 && info->clock_speed_index < 2)
3192 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003193 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003194}
3195
Martin Roth468d02c2019-10-23 21:44:42 -06003196static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003197{
Martin Roth468d02c2019-10-23 21:44:42 -06003198 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003199 if (a > b) {
3200 t = a;
3201 a = b;
3202 b = t;
3203 }
3204 /* invariant a < b. */
3205 while (a) {
3206 t = b % a;
3207 b = a;
3208 a = t;
3209 }
3210 return b;
3211}
3212
3213static inline int div_roundup(int a, int b)
3214{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003215 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003216}
3217
Martin Roth468d02c2019-10-23 21:44:42 -06003218static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003219{
3220 return (a * b) / gcd(a, b);
3221}
3222
3223struct stru1 {
3224 u8 freqs_reversed;
3225 u8 freq_diff_reduced;
3226 u8 freq_min_reduced;
3227 u8 divisor_f4_to_fmax;
3228 u8 divisor_f3_to_fmax;
3229 u8 freq4_to_max_remainder;
3230 u8 freq3_to_2_remainder;
3231 u8 freq3_to_2_remaindera;
3232 u8 freq4_to_2_remainder;
3233 int divisor_f3_to_f1, divisor_f4_to_f2;
3234 int common_time_unit_ps;
3235 int freq_max_reduced;
3236};
3237
3238static void
3239compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3240 int num_cycles_2, int num_cycles_1, int round_it,
3241 int add_freqs, struct stru1 *result)
3242{
3243 int g;
3244 int common_time_unit_ps;
3245 int freq1_reduced, freq2_reduced;
3246 int freq_min_reduced;
3247 int freq_max_reduced;
3248 int freq3, freq4;
3249
3250 g = gcd(freq1, freq2);
3251 freq1_reduced = freq1 / g;
3252 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003253 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3254 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003255
3256 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3257 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3258 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3259 if (add_freqs) {
3260 freq3 += freq2_reduced;
3261 freq4 += freq1_reduced;
3262 }
3263
3264 if (round_it) {
3265 result->freq3_to_2_remainder = 0;
3266 result->freq3_to_2_remaindera = 0;
3267 result->freq4_to_max_remainder = 0;
3268 result->divisor_f4_to_f2 = 0;
3269 result->divisor_f3_to_f1 = 0;
3270 } else {
3271 if (freq2_reduced < freq1_reduced) {
3272 result->freq3_to_2_remainder =
3273 result->freq3_to_2_remaindera =
3274 freq3 % freq1_reduced - freq1_reduced + 1;
3275 result->freq4_to_max_remainder =
3276 -(freq4 % freq1_reduced);
3277 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3278 result->divisor_f4_to_f2 =
3279 (freq4 -
3280 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3281 result->freq4_to_2_remainder =
3282 -(char)((freq1_reduced - freq2_reduced) +
3283 ((u8) freq4 -
3284 (freq1_reduced -
3285 freq2_reduced)) % (u8) freq2_reduced);
3286 } else {
3287 if (freq2_reduced > freq1_reduced) {
3288 result->freq4_to_max_remainder =
3289 (freq4 % freq2_reduced) - freq2_reduced + 1;
3290 result->freq4_to_2_remainder =
3291 freq4 % freq_max_reduced -
3292 freq_max_reduced + 1;
3293 } else {
3294 result->freq4_to_max_remainder =
3295 -(freq4 % freq2_reduced);
3296 result->freq4_to_2_remainder =
3297 -(char)(freq4 % freq_max_reduced);
3298 }
3299 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3300 result->divisor_f3_to_f1 =
3301 (freq3 -
3302 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3303 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3304 result->freq3_to_2_remaindera =
3305 -(char)((freq_max_reduced - freq_min_reduced) +
3306 (freq3 -
3307 (freq_max_reduced -
3308 freq_min_reduced)) % freq1_reduced);
3309 }
3310 }
3311 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3312 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3313 if (round_it) {
3314 if (freq2_reduced > freq1_reduced) {
3315 if (freq3 % freq_max_reduced)
3316 result->divisor_f3_to_fmax++;
3317 }
3318 if (freq2_reduced < freq1_reduced) {
3319 if (freq4 % freq_max_reduced)
3320 result->divisor_f4_to_fmax++;
3321 }
3322 }
3323 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3324 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3325 result->freq_min_reduced = freq_min_reduced;
3326 result->common_time_unit_ps = common_time_unit_ps;
3327 result->freq_max_reduced = freq_max_reduced;
3328}
3329
3330static void
3331set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3332 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3333 int num_cycles_4, int reverse)
3334{
3335 struct stru1 vv;
3336 char multiplier;
3337
3338 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3339 0, 1, &vv);
3340
3341 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003342 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003343 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3344 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3345 div_roundup(num_cycles_1,
3346 vv.common_time_unit_ps) +
3347 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3348 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3349
3350 u32 y =
3351 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3352 vv.freq_max_reduced * multiplier)
3353 | (vv.
3354 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3355 multiplier) << 16) | ((u8) (vv.
3356 freq_min_reduced
3357 *
3358 multiplier)
3359 << 24);
3360 u32 x =
3361 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3362 divisor_f3_to_f1
3363 << 16)
3364 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3365 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003366 MCHBAR32(reg) = y;
3367 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003368 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003369 MCHBAR32(reg + 4) = y;
3370 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003371 }
3372}
3373
3374static void
3375set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3376 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3377 int num_cycles_4)
3378{
3379 struct stru1 ratios1;
3380 struct stru1 ratios2;
3381
3382 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3383 0, 1, &ratios2);
3384 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3385 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003386 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003387 ratios1.freq4_to_max_remainder | (ratios2.
3388 freq4_to_max_remainder
3389 << 8)
3390 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3391 divisor_f4_to_fmax
3392 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003393 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3394 (ratios2.freq4_to_max_remainder << 8) |
3395 (ratios1.divisor_f4_to_fmax << 16) |
3396 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003397}
3398
3399static void
3400set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3401 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3402{
3403 struct stru1 ratios;
3404
3405 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3406 round_it, add_freqs, &ratios);
3407 switch (mode) {
3408 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003409 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3410 (ratios.freqs_reversed << 8);
3411 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3412 (ratios.freq4_to_max_remainder << 8) |
3413 (ratios.divisor_f3_to_fmax << 16) |
3414 (ratios.divisor_f4_to_fmax << 20) |
3415 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416 break;
3417
3418 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003419 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3420 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003421 break;
3422
3423 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003424 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3425 (ratios.freq4_to_max_remainder << 8) |
3426 (ratios.divisor_f3_to_fmax << 16) |
3427 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003428 break;
3429
3430 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003431 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3432 (ratios.divisor_f4_to_fmax << 8) |
3433 (ratios.freqs_reversed << 12) |
3434 (ratios.freq_min_reduced << 16) |
3435 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003436 break;
3437 }
3438}
3439
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003440static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003441{
3442 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3443 0, 1);
3444 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3445 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3446 1);
3447 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3448 frequency_11(info), 1231, 1524, 0, 1);
3449 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3450 frequency_11(info) / 2, 1278, 2008, 0, 1);
3451 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3452 1167, 1539, 0, 1);
3453 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3454 frequency_11(info) / 2, 1403, 1318, 0, 1);
3455 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3456 1);
3457 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3458 1);
3459 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3460 1, 1);
3461 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3462 1);
3463 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3464 frequency_11(info) / 2, 4000, 0, 0, 0);
3465 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3466 frequency_11(info) / 2, 4000, 4000, 0, 0);
3467
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003468 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003469 printk(RAM_SPEW, "[6dc] <= %x\n",
3470 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003471 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003472 } else
3473 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3474 info->delay46_ps[0], 0,
3475 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003476 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3477 frequency_11(info), 2500, 0, 0, 0);
3478 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3479 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003480 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003481 printk(RAM_SPEW, "[6e8] <= %x\n",
3482 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003483 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003484 } else
3485 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3486 info->delay46_ps[1], 0,
3487 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3489 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3490 470, 0);
3491 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3492 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3493 454, 459, 0);
3494 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3495 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3496 2588, 0);
3497 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3498 2405, 0);
3499 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3500 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3501 480, 0);
3502 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003503 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3504 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003505}
3506
3507static u16 get_max_timing(struct raminfo *info, int channel)
3508{
3509 int slot, rank, lane;
3510 u16 ret = 0;
3511
Felix Held04be2dd2018-07-29 04:53:22 +02003512 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003513 return 384;
3514
3515 if (info->revision < 8)
3516 return 256;
3517
3518 for (slot = 0; slot < NUM_SLOTS; slot++)
3519 for (rank = 0; rank < NUM_RANKS; rank++)
3520 if (info->populated_ranks[channel][slot][rank])
3521 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003522 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003523 get_timing_register_addr
3524 (lane, 0, slot,
3525 rank), 9));
3526 return ret;
3527}
3528
3529static void set_274265(struct raminfo *info)
3530{
3531 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3532 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3533 int delay_e_over_cycle_ps;
3534 int cycletime_ps;
3535 int channel;
3536
3537 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003538 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003539 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3540 cycletime_ps =
3541 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3542 delay_d_ps =
3543 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3544 - info->some_delay_3_ps_rounded + 200;
3545 if (!
3546 ((info->silicon_revision == 0
3547 || info->silicon_revision == 1)
3548 && (info->revision >= 8)))
3549 delay_d_ps += halfcycle_ps(info) * 2;
3550 delay_d_ps +=
3551 halfcycle_ps(info) * (!info->revision_flag_1 +
3552 info->some_delay_2_halfcycles_ceil +
3553 2 * info->some_delay_1_cycle_floor +
3554 info->clock_speed_index +
3555 2 * info->cas_latency - 7 + 11);
3556 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3557
Felix Held04be2dd2018-07-29 04:53:22 +02003558 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3559 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3560 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003561 delay_d_ps += 650;
3562 delay_c_ps = delay_d_ps + 1800;
3563 if (delay_c_ps <= delay_a_ps)
3564 delay_e_ps = 0;
3565 else
3566 delay_e_ps =
3567 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3568 cycletime_ps);
3569
3570 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3571 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3572 delay_f_cycles =
3573 div_roundup(2500 - delay_e_over_cycle_ps,
3574 2 * halfcycle_ps(info));
3575 if (delay_f_cycles > delay_e_cycles) {
3576 info->delay46_ps[channel] = delay_e_ps;
3577 delay_e_cycles = 0;
3578 } else {
3579 info->delay46_ps[channel] =
3580 delay_e_over_cycle_ps +
3581 2 * halfcycle_ps(info) * delay_f_cycles;
3582 delay_e_cycles -= delay_f_cycles;
3583 }
3584
3585 if (info->delay46_ps[channel] < 2500) {
3586 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003587 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003588 }
3589 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3590 if (delay_b_ps <= delay_a_ps)
3591 delay_b_ps = 0;
3592 else
3593 delay_b_ps -= delay_a_ps;
3594 info->delay54_ps[channel] =
3595 cycletime_ps * div_roundup(delay_b_ps,
3596 cycletime_ps) -
3597 2 * halfcycle_ps(info) * delay_e_cycles;
3598 if (info->delay54_ps[channel] < 2500)
3599 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003600 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003601 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3602 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003603 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003604 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003605 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003606 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3607 4 * halfcycle_ps(info)) - 6;
3608 MCHBAR32((channel << 10) + 0x274) =
3609 info->training.reg274265[channel][1] |
3610 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003611 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003612 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3613 4 * halfcycle_ps(info)) + 1;
3614 MCHBAR16((channel << 10) + 0x265) =
3615 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003617 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003618 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619 else
Felix Held04be2dd2018-07-29 04:53:22 +02003620 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621}
3622
3623static void restore_274265(struct raminfo *info)
3624{
3625 int channel;
3626
3627 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003628 MCHBAR32((channel << 10) + 0x274) =
3629 (info->cached_training->reg274265[channel][0] << 16) |
3630 info->cached_training->reg274265[channel][1];
3631 MCHBAR16((channel << 10) + 0x265) =
3632 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003633 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003634 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003635 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636 else
Felix Held04be2dd2018-07-29 04:53:22 +02003637 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638}
3639
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640static void dmi_setup(void)
3641{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003642 gav(read8(DEFAULT_DMIBAR + 0x254));
3643 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3644 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003645 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003646
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003647 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648
3649 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3650 DEFAULT_GPIOBASE | 0x38);
3651 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3652}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003653
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003654void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003657 u16 ggc;
3658 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659
Felix Held04be2dd2018-07-29 04:53:22 +02003660 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3662 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003663 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003664 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665 }
Felix Held29a9c072018-07-29 01:34:45 +02003666#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667 if (!s3resume) {
3668 pre_raminit_3(x2ca8);
3669 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003670 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671#endif
3672
3673 dmi_setup();
3674
Felix Held04be2dd2018-07-29 04:53:22 +02003675 MCHBAR16(0x1170) = 0xa880;
3676 MCHBAR8(0x11c1) = 0x1;
3677 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003678 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003679
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003680 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3681 /* 0 for 32MB */
3682 gfxsize = 0;
3683 }
3684
3685 ggc = 0xb00 | ((gfxsize + 5) << 4);
3686
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003687 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003688
3689 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003690 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691
3692 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003693 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003694 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003695 MCHBAR16_OR(0x2c30, 0x200);
3696 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003697 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003698 pci_read_config8(GMA, 0x62); // = 0x2
3699 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003700 read8(DEFAULT_RCBA + 0x2318);
3701 write8(DEFAULT_RCBA + 0x2318, 0x47);
3702 read8(DEFAULT_RCBA + 0x2320);
3703 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003704 }
3705
Felix Heldf83d80b2018-07-29 05:30:30 +02003706 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003707
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003708 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003709 gav(read32(DEFAULT_RCBA + 0x3428));
3710 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003711}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003713void raminit(const int s3resume, const u8 *spd_addrmap)
3714{
Martin Roth468d02c2019-10-23 21:44:42 -06003715 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003716 int i;
3717 struct raminfo info;
3718 u8 x2ca8;
3719 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003720 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003721
Felix Held04be2dd2018-07-29 04:53:22 +02003722 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003723
3724 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3725
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003726 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727
3728 memset(&info, 0x5a, sizeof(info));
3729
3730 info.last_500_command[0] = 0;
3731 info.last_500_command[1] = 0;
3732
3733 info.fsb_frequency = 135 * 2;
3734 info.board_lane_delay[0] = 0x14;
3735 info.board_lane_delay[1] = 0x07;
3736 info.board_lane_delay[2] = 0x07;
3737 info.board_lane_delay[3] = 0x08;
3738 info.board_lane_delay[4] = 0x56;
3739 info.board_lane_delay[5] = 0x04;
3740 info.board_lane_delay[6] = 0x04;
3741 info.board_lane_delay[7] = 0x05;
3742 info.board_lane_delay[8] = 0x10;
3743
3744 info.training.reg_178 = 0;
3745 info.training.reg_10b = 0;
3746
3747 info.heci_bar = 0;
3748 info.memory_reserved_for_heci_mb = 0;
3749
3750 /* before SPD */
3751 timestamp_add_now(101);
3752
Felix Held29a9c072018-07-29 01:34:45 +02003753 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003754 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003755
3756 collect_system_info(&info);
3757
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003758 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3759
3760 info.use_ecc = 1;
3761 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003762 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763 int v;
3764 int try;
3765 int addr;
3766 const u8 useful_addresses[] = {
3767 DEVICE_TYPE,
3768 MODULE_TYPE,
3769 DENSITY,
3770 RANKS_AND_DQ,
3771 MEMORY_BUS_WIDTH,
3772 TIMEBASE_DIVIDEND,
3773 TIMEBASE_DIVISOR,
3774 CYCLETIME,
3775 CAS_LATENCIES_LSB,
3776 CAS_LATENCIES_MSB,
3777 CAS_LATENCY_TIME,
3778 0x11, 0x12, 0x13, 0x14, 0x15,
3779 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3780 0x1c, 0x1d,
3781 THERMAL_AND_REFRESH,
3782 0x20,
3783 REFERENCE_RAW_CARD_USED,
3784 RANK1_ADDRESS_MAPPING,
3785 0x75, 0x76, 0x77, 0x78,
3786 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3787 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3788 0x85, 0x86, 0x87, 0x88,
3789 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3790 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3791 0x95
3792 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003793 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003794 continue;
3795 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003796 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003797 DEVICE_TYPE);
3798 if (v >= 0)
3799 break;
3800 }
3801 if (v < 0)
3802 continue;
3803 for (addr = 0;
3804 addr <
3805 sizeof(useful_addresses) /
3806 sizeof(useful_addresses[0]); addr++)
3807 gav(info.
3808 spd[channel][0][useful_addresses
3809 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003810 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003811 useful_addresses
3812 [addr]));
3813 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3814 die("Only DDR3 is supported");
3815
3816 v = info.spd[channel][0][RANKS_AND_DQ];
3817 info.populated_ranks[channel][0][0] = 1;
3818 info.populated_ranks[channel][0][1] =
3819 ((v >> 3) & 7);
3820 if (((v >> 3) & 7) > 1)
3821 die("At most 2 ranks are supported");
3822 if ((v & 7) == 0 || (v & 7) > 2)
3823 die("Only x8 and x16 modules are supported");
3824 if ((info.
3825 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3826 && (info.
3827 spd[channel][slot][MODULE_TYPE] & 0xF)
3828 != 3)
3829 die("Registered memory is not supported");
3830 info.is_x16_module[channel][0] = (v & 7) - 1;
3831 info.density[channel][slot] =
3832 info.spd[channel][slot][DENSITY] & 0xF;
3833 if (!
3834 (info.
3835 spd[channel][slot][MEMORY_BUS_WIDTH] &
3836 0x18))
3837 info.use_ecc = 0;
3838 }
3839
3840 gav(0x55);
3841
3842 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3843 int v = 0;
3844 for (slot = 0; slot < NUM_SLOTS; slot++)
3845 for (rank = 0; rank < NUM_RANKS; rank++)
3846 v |= info.
3847 populated_ranks[channel][slot][rank]
3848 << (2 * slot + rank);
3849 info.populated_ranks_mask[channel] = v;
3850 }
3851
3852 gav(0x55);
3853
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003854 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855 }
3856
3857 /* after SPD */
3858 timestamp_add_now(102);
3859
Felix Held04be2dd2018-07-29 04:53:22 +02003860 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861
3862 collect_system_info(&info);
3863 calculate_timings(&info);
3864
Felix Held29a9c072018-07-29 01:34:45 +02003865#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003866 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867#endif
3868
3869 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003870 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871 if (x2ca8 == 0 && (reg8 & 0x80)) {
3872 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3873 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3874 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3875 */
3876
3877 /* Clear bit7. */
3878
3879 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3880 (reg8 & ~(1 << 7)));
3881
3882 printk(BIOS_INFO,
3883 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003884 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003885 }
3886 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003887
3888 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003889 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3890 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003891
3892 compute_derived_timings(&info);
3893
3894 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003895 gav(MCHBAR8(0x164));
3896 MCHBAR8(0x164) = 0x26;
3897 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003898 }
3899
Felix Held04be2dd2018-07-29 04:53:22 +02003900 MCHBAR32_OR(0x18b4, 0x210000);
3901 MCHBAR32_OR(0x1890, 0x2000000);
3902 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003903
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003904 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3905 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906
Felix Held04be2dd2018-07-29 04:53:22 +02003907 gav(MCHBAR16(0x2c10));
3908 MCHBAR16(0x2c10) = 0x412;
3909 gav(MCHBAR16(0x2c10));
3910 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911
Felix Held04be2dd2018-07-29 04:53:22 +02003912 gav(MCHBAR8(0x2ca8)); // !!!!
3913 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003914
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003915 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3916 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003917 gav(MCHBAR32(0x1c04)); // !!!!
3918 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
3920 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003921 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922 }
3923
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR32(0x18d8) = 0x120000;
3925 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003926 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3927 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003928 MCHBAR32(0x18d8) = 0x40000;
3929 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003930 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3931 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003932 MCHBAR32(0x18d8) = 0x180000;
3933 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003934 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3935 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003936 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003937
Felix Held04be2dd2018-07-29 04:53:22 +02003938 gav(MCHBAR32(0x18dc)); // !!!!
3939 MCHBAR32(0x18dc) = 0x3;
3940 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003941
3942 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003943 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003944 }
3945
Felix Held04be2dd2018-07-29 04:53:22 +02003946 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003947 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003948 MCHBAR32(0x1a10) = 0x4200010e;
3949 MCHBAR32_OR(0x18b8, 0x200);
3950 gav(MCHBAR32(0x1918)); // !!!!
3951 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952
Felix Held04be2dd2018-07-29 04:53:22 +02003953 gav(MCHBAR32(0x18b8)); // !!!!
3954 MCHBAR32(0x18b8) = 0xe00;
3955 gav(MCHBAR32(0x182c)); // !!!!
3956 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003957 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3958 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003959 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3960 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003961
Felix Held04be2dd2018-07-29 04:53:22 +02003962 MCHBAR32_AND(0x18b4, 0xffff7fff);
3963 gav(MCHBAR32(0x1a68)); // !!!!
3964 MCHBAR32(0x1a68) = 0x343800;
3965 gav(MCHBAR32(0x1e68)); // !!!!
3966 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967
3968 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003969 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003970 }
3971
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003972 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3973 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3974 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3975 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3976 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3977 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3978 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003979 gav(MCHBAR32(0x1af0)); // !!!!
3980 gav(MCHBAR32(0x1af0)); // !!!!
3981 MCHBAR32(0x1af0) = 0x1f020003;
3982 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003983
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003984 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003985 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003986 }
3987
Felix Held04be2dd2018-07-29 04:53:22 +02003988 gav(MCHBAR32(0x1890)); // !!!!
3989 MCHBAR32(0x1890) = 0x80102;
3990 gav(MCHBAR32(0x18b4)); // !!!!
3991 MCHBAR32(0x18b4) = 0x216000;
3992 MCHBAR32(0x18a4) = 0x22222222;
3993 MCHBAR32(0x18a8) = 0x22222222;
3994 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003995
3996 udelay(1000);
3997
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003998 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003999
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004000 if (x2ca8 == 0) {
4001 int j;
4002 if (s3resume && info.cached_training) {
4003 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004004 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004005 info.cached_training->reg2ca9_bit0);
4006 for (i = 0; i < 2; i++)
4007 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004008 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004009 i, j, info.cached_training->reg274265[i][j]);
4010 } else {
4011 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004012 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004013 info.training.reg2ca9_bit0);
4014 for (i = 0; i < 2; i++)
4015 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004016 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004017 i, j, info.training.reg274265[i][j]);
4018 }
4019
4020 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004021
4022 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004023 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004024 }
4025
4026 udelay(1000);
4027
4028 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004029 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004030 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004031 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4032 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4033 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004034
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004035 MCHBAR8(0x1150);
4036 MCHBAR8(0x1151);
4037 MCHBAR8(0x1022);
4038 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004039 MCHBAR32(0x1300) = 0x60606060;
4040 MCHBAR32(0x1304) = 0x60606060;
4041 MCHBAR32(0x1308) = 0x78797a7b;
4042 MCHBAR32(0x130c) = 0x7c7d7e7f;
4043 MCHBAR32(0x1310) = 0x60606060;
4044 MCHBAR32(0x1314) = 0x60606060;
4045 MCHBAR32(0x1318) = 0x60606060;
4046 MCHBAR32(0x131c) = 0x60606060;
4047 MCHBAR32(0x1320) = 0x50515253;
4048 MCHBAR32(0x1324) = 0x54555657;
4049 MCHBAR32(0x1328) = 0x58595a5b;
4050 MCHBAR32(0x132c) = 0x5c5d5e5f;
4051 MCHBAR32(0x1330) = 0x40414243;
4052 MCHBAR32(0x1334) = 0x44454647;
4053 MCHBAR32(0x1338) = 0x48494a4b;
4054 MCHBAR32(0x133c) = 0x4c4d4e4f;
4055 MCHBAR32(0x1340) = 0x30313233;
4056 MCHBAR32(0x1344) = 0x34353637;
4057 MCHBAR32(0x1348) = 0x38393a3b;
4058 MCHBAR32(0x134c) = 0x3c3d3e3f;
4059 MCHBAR32(0x1350) = 0x20212223;
4060 MCHBAR32(0x1354) = 0x24252627;
4061 MCHBAR32(0x1358) = 0x28292a2b;
4062 MCHBAR32(0x135c) = 0x2c2d2e2f;
4063 MCHBAR32(0x1360) = 0x10111213;
4064 MCHBAR32(0x1364) = 0x14151617;
4065 MCHBAR32(0x1368) = 0x18191a1b;
4066 MCHBAR32(0x136c) = 0x1c1d1e1f;
4067 MCHBAR32(0x1370) = 0x10203;
4068 MCHBAR32(0x1374) = 0x4050607;
4069 MCHBAR32(0x1378) = 0x8090a0b;
4070 MCHBAR32(0x137c) = 0xc0d0e0f;
4071 MCHBAR8(0x11cc) = 0x4e;
4072 MCHBAR32(0x1110) = 0x73970404;
4073 MCHBAR32(0x1114) = 0x72960404;
4074 MCHBAR32(0x1118) = 0x6f950404;
4075 MCHBAR32(0x111c) = 0x6d940404;
4076 MCHBAR32(0x1120) = 0x6a930404;
4077 MCHBAR32(0x1124) = 0x68a41404;
4078 MCHBAR32(0x1128) = 0x66a21404;
4079 MCHBAR32(0x112c) = 0x63a01404;
4080 MCHBAR32(0x1130) = 0x609e1404;
4081 MCHBAR32(0x1134) = 0x5f9c1404;
4082 MCHBAR32(0x1138) = 0x5c961404;
4083 MCHBAR32(0x113c) = 0x58a02404;
4084 MCHBAR32(0x1140) = 0x54942404;
4085 MCHBAR32(0x1190) = 0x900080a;
4086 MCHBAR16(0x11c0) = 0xc40b;
4087 MCHBAR16(0x11c2) = 0x303;
4088 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004089 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004090 MCHBAR32(0x11b8) = 0x70c3000;
4091 MCHBAR8(0x11ec) = 0xa;
4092 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004093 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004094 MCHBAR16(0x11ca) = 0xfa;
4095 MCHBAR32(0x11e4) = 0x4e20;
4096 MCHBAR8(0x11bc) = 0xf;
4097 MCHBAR16(0x11da) = 0x19;
4098 MCHBAR16(0x11ba) = 0x470c;
4099 MCHBAR32(0x1680) = 0xe6ffe4ff;
4100 MCHBAR32(0x1684) = 0xdeffdaff;
4101 MCHBAR32(0x1688) = 0xd4ffd0ff;
4102 MCHBAR32(0x168c) = 0xccffc6ff;
4103 MCHBAR32(0x1690) = 0xc0ffbeff;
4104 MCHBAR32(0x1694) = 0xb8ffb0ff;
4105 MCHBAR32(0x1698) = 0xa8ff0000;
4106 MCHBAR32(0x169c) = 0xc00;
4107 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004108 }
4109
Felix Held04be2dd2018-07-29 04:53:22 +02004110 MCHBAR32(0x124c) = 0x15040d00;
4111 MCHBAR32(0x1250) = 0x7f0000;
4112 MCHBAR32(0x1254) = 0x1e220004;
4113 MCHBAR32(0x1258) = 0x4000004;
4114 MCHBAR32(0x1278) = 0x0;
4115 MCHBAR32(0x125c) = 0x0;
4116 MCHBAR32(0x1260) = 0x0;
4117 MCHBAR32(0x1264) = 0x0;
4118 MCHBAR32(0x1268) = 0x0;
4119 MCHBAR32(0x126c) = 0x0;
4120 MCHBAR32(0x1270) = 0x0;
4121 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004122 }
4123
4124 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004125 MCHBAR16(0x1214) = 0x320;
4126 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004127 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4128 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004129 MCHBAR32(0x1400) = 0x13040020;
4130 MCHBAR32(0x1404) = 0xe090120;
4131 MCHBAR32(0x1408) = 0x5120220;
4132 MCHBAR32(0x140c) = 0x5120330;
4133 MCHBAR32(0x1410) = 0xe090220;
4134 MCHBAR32(0x1414) = 0x1010001;
4135 MCHBAR32(0x1418) = 0x1110000;
4136 MCHBAR32(0x141c) = 0x9020020;
4137 MCHBAR32(0x1420) = 0xd090220;
4138 MCHBAR32(0x1424) = 0x2090220;
4139 MCHBAR32(0x1428) = 0x2090330;
4140 MCHBAR32(0x142c) = 0xd090220;
4141 MCHBAR32(0x1430) = 0x1010001;
4142 MCHBAR32(0x1434) = 0x1110000;
4143 MCHBAR32(0x1438) = 0x11040020;
4144 MCHBAR32(0x143c) = 0x4030220;
4145 MCHBAR32(0x1440) = 0x1060220;
4146 MCHBAR32(0x1444) = 0x1060330;
4147 MCHBAR32(0x1448) = 0x4030220;
4148 MCHBAR32(0x144c) = 0x1010001;
4149 MCHBAR32(0x1450) = 0x1110000;
4150 MCHBAR32(0x1454) = 0x4010020;
4151 MCHBAR32(0x1458) = 0xb090220;
4152 MCHBAR32(0x145c) = 0x1090220;
4153 MCHBAR32(0x1460) = 0x1090330;
4154 MCHBAR32(0x1464) = 0xb090220;
4155 MCHBAR32(0x1468) = 0x1010001;
4156 MCHBAR32(0x146c) = 0x1110000;
4157 MCHBAR32(0x1470) = 0xf040020;
4158 MCHBAR32(0x1474) = 0xa090220;
4159 MCHBAR32(0x1478) = 0x1120220;
4160 MCHBAR32(0x147c) = 0x1120330;
4161 MCHBAR32(0x1480) = 0xa090220;
4162 MCHBAR32(0x1484) = 0x1010001;
4163 MCHBAR32(0x1488) = 0x1110000;
4164 MCHBAR32(0x148c) = 0x7020020;
4165 MCHBAR32(0x1490) = 0x1010220;
4166 MCHBAR32(0x1494) = 0x10210;
4167 MCHBAR32(0x1498) = 0x10320;
4168 MCHBAR32(0x149c) = 0x1010220;
4169 MCHBAR32(0x14a0) = 0x1010001;
4170 MCHBAR32(0x14a4) = 0x1110000;
4171 MCHBAR32(0x14a8) = 0xd040020;
4172 MCHBAR32(0x14ac) = 0x8090220;
4173 MCHBAR32(0x14b0) = 0x1111310;
4174 MCHBAR32(0x14b4) = 0x1111420;
4175 MCHBAR32(0x14b8) = 0x8090220;
4176 MCHBAR32(0x14bc) = 0x1010001;
4177 MCHBAR32(0x14c0) = 0x1110000;
4178 MCHBAR32(0x14c4) = 0x3010020;
4179 MCHBAR32(0x14c8) = 0x7090220;
4180 MCHBAR32(0x14cc) = 0x1081310;
4181 MCHBAR32(0x14d0) = 0x1081420;
4182 MCHBAR32(0x14d4) = 0x7090220;
4183 MCHBAR32(0x14d8) = 0x1010001;
4184 MCHBAR32(0x14dc) = 0x1110000;
4185 MCHBAR32(0x14e0) = 0xb040020;
4186 MCHBAR32(0x14e4) = 0x2030220;
4187 MCHBAR32(0x14e8) = 0x1051310;
4188 MCHBAR32(0x14ec) = 0x1051420;
4189 MCHBAR32(0x14f0) = 0x2030220;
4190 MCHBAR32(0x14f4) = 0x1010001;
4191 MCHBAR32(0x14f8) = 0x1110000;
4192 MCHBAR32(0x14fc) = 0x5020020;
4193 MCHBAR32(0x1500) = 0x5090220;
4194 MCHBAR32(0x1504) = 0x2071310;
4195 MCHBAR32(0x1508) = 0x2071420;
4196 MCHBAR32(0x150c) = 0x5090220;
4197 MCHBAR32(0x1510) = 0x1010001;
4198 MCHBAR32(0x1514) = 0x1110000;
4199 MCHBAR32(0x1518) = 0x7040120;
4200 MCHBAR32(0x151c) = 0x2090220;
4201 MCHBAR32(0x1520) = 0x70b1210;
4202 MCHBAR32(0x1524) = 0x70b1310;
4203 MCHBAR32(0x1528) = 0x2090220;
4204 MCHBAR32(0x152c) = 0x1010001;
4205 MCHBAR32(0x1530) = 0x1110000;
4206 MCHBAR32(0x1534) = 0x1010110;
4207 MCHBAR32(0x1538) = 0x1081310;
4208 MCHBAR32(0x153c) = 0x5041200;
4209 MCHBAR32(0x1540) = 0x5041310;
4210 MCHBAR32(0x1544) = 0x1081310;
4211 MCHBAR32(0x1548) = 0x1010001;
4212 MCHBAR32(0x154c) = 0x1110000;
4213 MCHBAR32(0x1550) = 0x1040120;
4214 MCHBAR32(0x1554) = 0x4051210;
4215 MCHBAR32(0x1558) = 0xd051200;
4216 MCHBAR32(0x155c) = 0xd051200;
4217 MCHBAR32(0x1560) = 0x4051210;
4218 MCHBAR32(0x1564) = 0x1010001;
4219 MCHBAR32(0x1568) = 0x1110000;
4220 MCHBAR16(0x1222) = 0x220a;
4221 MCHBAR16(0x123c) = 0x1fc0;
4222 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004223 }
4224
Felix Heldf83d80b2018-07-29 05:30:30 +02004225 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004226 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004227 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004228
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004229 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004230
4231 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004232 MCHBAR8_AND(0x2ca8, ~3);
4233 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004234 /* This issues a CPU reset without resetting the platform */
4235 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004236 /* Write back the S3 state to PM1_CNT to let the reset CPU
4237 know it also needs to take the s3 path. */
4238 if (s3resume)
4239 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4240 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004241 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004242 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004243 }
4244
Felix Held04be2dd2018-07-29 04:53:22 +02004245 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004246 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004247 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004248 MCHBAR16(0x2c20); // !!!!
4249 MCHBAR16(0x2c10); // !!!!
4250 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004251 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004252 udelay(1000);
4253 write_1d0(0, 0x33d, 0, 0);
4254 write_500(&info, 0, 0, 0xb61, 0, 0);
4255 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004256 MCHBAR32(0x1a30) = 0x0;
4257 MCHBAR32(0x1a34) = 0x0;
4258 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4259 (info.populated_ranks[0][0][0] * 0xa0);
4260 MCHBAR16(0x616) = 0x26a;
4261 MCHBAR32(0x134) = 0x856000;
4262 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004263 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4264 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004265 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004266 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4267 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004268 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004269 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004270 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4271 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004272 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4273 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4274 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4275 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4276 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4277 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4278 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4279 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4280 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4281 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004282 }
4283
4284 write_1d0(0x4, 0x151, 4, 1);
4285 write_1d0(0, 0x142, 3, 1);
4286 rdmsr(0x1ac); // !!!!
4287 write_500(&info, 1, 1, 0x6b3, 4, 1);
4288 write_500(&info, 1, 1, 0x6cf, 4, 1);
4289
4290 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4291
4292 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4293 populated_ranks[0]
4294 [0][0]) << 0),
4295 0x1d1, 3, 1);
4296 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004297 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4298 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004299 }
4300
4301 set_334(0);
4302
4303 program_base_timings(&info);
4304
Felix Held04be2dd2018-07-29 04:53:22 +02004305 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004306
4307 write_1d0(0x2, 0x1d5, 2, 1);
4308 write_1d0(0x20, 0x166, 7, 1);
4309 write_1d0(0x0, 0xeb, 3, 1);
4310 write_1d0(0x0, 0xf3, 6, 1);
4311
4312 for (channel = 0; channel < NUM_CHANNELS; channel++)
4313 for (lane = 0; lane < 9; lane++) {
4314 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4315 u8 a;
4316 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4317 write_500(&info, channel, a, addr, 6, 1);
4318 }
4319
4320 udelay(1000);
4321
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004322 if (s3resume) {
4323 if (info.cached_training == NULL) {
4324 u32 reg32;
4325 printk(BIOS_ERR,
4326 "Couldn't find training data. Rebooting\n");
4327 reg32 = inl(DEFAULT_PMBASE + 0x04);
4328 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004329 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004330 }
4331 int tm;
4332 info.training = *info.cached_training;
4333 for (tm = 0; tm < 4; tm++)
4334 for (channel = 0; channel < NUM_CHANNELS; channel++)
4335 for (slot = 0; slot < NUM_SLOTS; slot++)
4336 for (rank = 0; rank < NUM_RANKS; rank++)
4337 for (lane = 0; lane < 9; lane++)
4338 write_500(&info,
4339 channel,
4340 info.training.
4341 lane_timings
4342 [tm][channel]
4343 [slot][rank]
4344 [lane],
4345 get_timing_register_addr
4346 (lane, tm,
4347 slot, rank),
4348 9, 0);
4349 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4350 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4351 }
4352
Felix Heldf83d80b2018-07-29 05:30:30 +02004353 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004354 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004355 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004356 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004357
4358 program_board_delay(&info);
4359
Felix Held04be2dd2018-07-29 04:53:22 +02004360 MCHBAR8(0x5ff) = 0x0;
4361 MCHBAR8(0x5ff) = 0x80;
4362 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004363
Felix Held04be2dd2018-07-29 04:53:22 +02004364 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004365 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004366 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004367 gav(read_1d0(0x14b, 7)); // = 0x81023100
4368 write_1d0(0x30, 0x14b, 7, 1);
4369 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4370 write_1d0(7, 0xd6, 6, 1);
4371 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4372 write_1d0(7, 0x328, 6, 1);
4373
4374 for (channel = 0; channel < NUM_CHANNELS; channel++)
4375 set_4cf(&info, channel,
4376 info.populated_ranks[channel][0][0] ? 8 : 0);
4377
4378 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4379 write_1d0(2, 0x116, 4, 1);
4380 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4381 write_1d0(0, 0xae, 6, 1);
4382 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4383 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004384 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4385 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004386 MCHBAR32_AND(0x140, ~0x07000000);
4387 MCHBAR32_AND(0x138, ~0x07000000);
4388 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004389 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004390 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004391 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004392
4393 {
4394 u32 t;
4395 u8 val_a1;
4396 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4397 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4398 rmw_1d0(0x320, 0x07,
4399 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4400 rmw_1d0(0x14b, 0x78,
4401 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4402 4), 7,
4403 1);
4404 rmw_1d0(0xce, 0x38,
4405 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4406 4), 6,
4407 1);
4408 }
4409
4410 for (channel = 0; channel < NUM_CHANNELS; channel++)
4411 set_4cf(&info, channel,
4412 info.populated_ranks[channel][0][0] ? 9 : 1);
4413
4414 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004415 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004416 write_1d0(2, 0xae, 6, 1);
4417 write_1d0(2, 0x300, 6, 1);
4418 write_1d0(2, 0x121, 3, 1);
4419 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4420 write_1d0(4, 0xd6, 6, 1);
4421 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4422 write_1d0(4, 0x328, 6, 1);
4423
4424 for (channel = 0; channel < NUM_CHANNELS; channel++)
4425 set_4cf(&info, channel,
4426 info.populated_ranks[channel][0][0] ? 9 : 0);
4427
Felix Held04be2dd2018-07-29 04:53:22 +02004428 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4429 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004430 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004431 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004432 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4433 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4434 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4435 write_1d0(0, 0x21c, 6, 1);
4436 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4437 write_1d0(0x35, 0x14b, 7, 1);
4438
4439 for (channel = 0; channel < NUM_CHANNELS; channel++)
4440 set_4cf(&info, channel,
4441 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4442
4443 set_334(1);
4444
Felix Held04be2dd2018-07-29 04:53:22 +02004445 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004446
4447 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4448 write_500(&info, channel,
4449 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4450 1);
4451 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4452 }
Felix Held04be2dd2018-07-29 04:53:22 +02004453 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4454 MCHBAR16(0x6c0) = 0x14a0;
4455 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4456 MCHBAR16(0x232) = 0x8;
4457 /* 0x40004 or 0 depending on ? */
4458 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4459 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4460 MCHBAR32(0x128) = 0x2150d05;
4461 MCHBAR8(0x12c) = 0x1f;
4462 MCHBAR8(0x12d) = 0x56;
4463 MCHBAR8(0x12e) = 0x31;
4464 MCHBAR8(0x12f) = 0x0;
4465 MCHBAR8(0x271) = 0x2;
4466 MCHBAR8(0x671) = 0x2;
4467 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004468 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004469 MCHBAR32(0x294 + (channel << 10)) =
4470 (info.populated_ranks_mask[channel] & 3) << 16;
4471 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4472 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004473 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004474 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4475 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476
4477 if (!s3resume)
4478 jedec_init(&info);
4479
4480 int totalrank = 0;
4481 for (channel = 0; channel < NUM_CHANNELS; channel++)
4482 for (slot = 0; slot < NUM_SLOTS; slot++)
4483 for (rank = 0; rank < NUM_RANKS; rank++)
4484 if (info.populated_ranks[channel][slot][rank]) {
4485 jedec_read(&info, channel, slot, rank,
4486 totalrank, 0xa, 0x400);
4487 totalrank++;
4488 }
4489
Felix Held04be2dd2018-07-29 04:53:22 +02004490 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004491
Felix Heldf83d80b2018-07-29 05:30:30 +02004492 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4493 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004494
4495 if (!s3resume) {
4496 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004497 MCHBAR32(0x294 + (channel << 10)) =
4498 (info.populated_ranks_mask[channel] & 3) << 16;
4499 MCHBAR16(0x298 + (channel << 10)) =
4500 info.populated_ranks[channel][0][0] |
4501 (info.populated_ranks[channel][0][1] << 5);
4502 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004503 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004504 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505
4506 {
4507 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004508 a = MCHBAR8(0x243);
4509 b = MCHBAR8(0x643);
4510 MCHBAR8(0x243) = a | 2;
4511 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512 }
4513
4514 write_1d0(7, 0x19b, 3, 1);
4515 write_1d0(7, 0x1c0, 3, 1);
4516 write_1d0(4, 0x1c6, 4, 1);
4517 write_1d0(4, 0x1cc, 4, 1);
4518 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4519 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004520 MCHBAR32(0x584) = 0xfffff;
4521 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522
4523 for (channel = 0; channel < NUM_CHANNELS; channel++)
4524 for (slot = 0; slot < NUM_SLOTS; slot++)
4525 for (rank = 0; rank < NUM_RANKS; rank++)
4526 if (info.
4527 populated_ranks[channel][slot]
4528 [rank])
4529 config_rank(&info, s3resume,
4530 channel, slot,
4531 rank);
4532
Felix Held04be2dd2018-07-29 04:53:22 +02004533 MCHBAR8(0x243) = 0x1;
4534 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004535 }
4536
4537 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004538 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004539 write_26c(0, 0x820);
4540 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004541 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004542 /* end */
4543
4544 if (s3resume) {
4545 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004546 MCHBAR32(0x294 + (channel << 10)) =
4547 (info.populated_ranks_mask[channel] & 3) << 16;
4548 MCHBAR16(0x298 + (channel << 10)) =
4549 info.populated_ranks[channel][0][0] |
4550 (info.populated_ranks[channel][0][1] << 5);
4551 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004552 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004553 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554 }
4555
Felix Held04be2dd2018-07-29 04:53:22 +02004556 MCHBAR32_AND(0xfa4, ~0x01000002);
4557 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 /* Before training. */
4560 timestamp_add_now(103);
4561
4562 if (!s3resume)
4563 ram_training(&info);
4564
4565 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004566 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004567
4568 dump_timings(&info);
4569
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 program_modules_memory_map(&info, 0);
4571 program_total_memory_map(&info);
4572
4573 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004574 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004576 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 else
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR32_AND(0xfac, ~0x80000000);
4583 MCHBAR32(0xfb4) = 0x4800;
4584 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4585 MCHBAR32(0xe94) = 0x7ffff;
4586 MCHBAR32(0xfc0) = 0x80002040;
4587 MCHBAR32(0xfc4) = 0x701246;
4588 MCHBAR8_AND(0xfc8, ~0x70);
4589 MCHBAR32_OR(0xe5c, 0x1000000);
4590 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4591 MCHBAR32(0x50) = 0x700b0;
4592 MCHBAR32(0x3c) = 0x10;
4593 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4594 MCHBAR8_OR(0xff4, 0x2);
4595 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596
Felix Held29a9c072018-07-29 01:34:45 +02004597#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4599 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4600 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004601
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004602 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4603 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4604 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004605
4606#else
4607 {
4608 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004609 // = 0xe911714b
4610 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4611 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4612 // = 0xe911714b
4613 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4614 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004615 }
4616#endif
4617
4618 {
4619 u32 eax;
4620
4621 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004622 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4623 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4624 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004625 }
4626
4627 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004628 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004629 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631 else
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
Felix Held04be2dd2018-07-29 04:53:22 +02004636 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004638 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 else
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641 }
4642
Felix Held04be2dd2018-07-29 04:53:22 +02004643 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644
4645 {
4646 u8 al;
4647 al = 0xd;
4648 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4649 al += 2;
4650 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652 }
4653
4654 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004655 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4656 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4657 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4658 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659 }
4660 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004661 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004662 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004663 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004664 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004665 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004666 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004667 MCHBAR8_OR(0x1210, 2);
4668 MCHBAR32(0x1200) = 0x8800440;
4669 MCHBAR32(0x1204) = 0x53ff0453;
4670 MCHBAR32(0x1208) = 0x19002043;
4671 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004672
4673 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR16(0x1214) = 0x220;
4675 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676 }
4677
Felix Held04be2dd2018-07-29 04:53:22 +02004678 MCHBAR8_OR(0x1214, 0x4);
4679 MCHBAR8(0x120c) = 0x1;
4680 MCHBAR8(0x1218) = 0x3;
4681 MCHBAR8(0x121a) = 0x3;
4682 MCHBAR8(0x121c) = 0x3;
4683 MCHBAR16(0xc14) = 0x0;
4684 MCHBAR16(0xc20) = 0x0;
4685 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004686
4687 /* revision dependent here. */
4688
Felix Held04be2dd2018-07-29 04:53:22 +02004689 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690
4691 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693
Felix Held04be2dd2018-07-29 04:53:22 +02004694 MCHBAR16_OR(0x1230, 0x8000);
4695 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004696
4697 u8 bl, ebpb;
4698 u16 reg_1020;
4699
Felix Held04be2dd2018-07-29 04:53:22 +02004700 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4701 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004702
Felix Held04be2dd2018-07-29 04:53:22 +02004703 MCHBAR32(0x1000) = 0x100;
4704 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705
4706 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004707 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004708 bl = reg_1020 >> 8;
4709 ebpb = reg_1020 & 0xff;
4710 } else {
4711 ebpb = 0;
4712 bl = 8;
4713 }
4714
4715 rdmsr(0x1a2);
4716
Felix Held04be2dd2018-07-29 04:53:22 +02004717 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004718
Felix Held04be2dd2018-07-29 04:53:22 +02004719 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720
Felix Held04be2dd2018-07-29 04:53:22 +02004721 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722
Felix Held04be2dd2018-07-29 04:53:22 +02004723 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4726 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727 }
4728
4729 setup_heci_uma(&info);
4730
4731 if (info.uma_enabled) {
4732 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004733 MCHBAR32_OR(0x11b0, 0x4000);
4734 MCHBAR32_OR(0x11b4, 0x4000);
4735 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004736
Felix Held04be2dd2018-07-29 04:53:22 +02004737 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4738 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4739 MCHBAR16_OR(0x1170, 0x1000);
4740
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004741 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004744 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004745 ;
4746 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004747 }
4748
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004749 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4750 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004751 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004752 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004753
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754 udelay(1000);
4755 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004756 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4757
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004758 if (!s3resume)
4759 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004760 if (s3resume && cbmem_wasnot_inited) {
4761 u32 reg32;
4762 printk(BIOS_ERR, "Failed S3 resume.\n");
4763 ram_check(0x100000, 0x200000);
4764
4765 /* Clear SLP_TYPE. */
4766 reg32 = inl(DEFAULT_PMBASE + 0x04);
4767 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4768
4769 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004770 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004771 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004772}