blob: 0efe1760fedb2f30c85ed9e8583108cbaf29f26e [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010058#include <lib.h> /* Prototypes */
59
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010060typedef struct _u128 {
61 u64 lo;
62 u64 hi;
63} u128;
64
65static void read128(u32 addr, u64 * out)
66{
67 u128 ret;
68 u128 stor;
69 asm volatile ("movdqu %%xmm0, %0\n"
70 "movdqa (%2), %%xmm0\n"
71 "movdqu %%xmm0, %1\n"
72 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
73 out[0] = ret.lo;
74 out[1] = ret.hi;
75}
76
Angel Ponsc2d6f5f2020-12-11 23:48:51 +010077/*
78 * Ironlake memory I/O timings are located in scan chains, accessible
79 * through MCHBAR register groups. Each channel has a scan chain, and
80 * there's a global scan chain too. Each chain is broken into smaller
81 * sections of N bits, where N <= 32. Each section allows reading and
82 * writing a certain parameter. Each section contains N - 2 data bits
83 * and two additional bits: a Mask bit, and a Halt bit.
84 */
85
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010086/* OK */
87static void write_1d0(u32 val, u16 addr, int bits, int flag)
88{
Felix Held04be2dd2018-07-29 04:53:22 +020089 MCHBAR32(0x1d0) = 0;
90 while (MCHBAR32(0x1d0) & 0x800000)
91 ;
92 MCHBAR32(0x1d4) =
93 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
94 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +020095 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +020096 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097}
98
99/* OK */
100static u16 read_1d0(u16 addr, int split)
101{
102 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200103 MCHBAR32(0x1d0) = 0;
104 while (MCHBAR32(0x1d0) & 0x800000)
105 ;
106 MCHBAR32(0x1d0) =
107 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
108 while (MCHBAR32(0x1d0) & 0x800000)
109 ;
110 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100111 write_1d0(0, 0x33d, 0, 0);
112 write_1d0(0, 0x33d, 0, 0);
113 val &= ((1 << split) - 1);
114 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
115 return val;
116}
117
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800118static void write32p(uintptr_t addr, uint32_t val)
119{
120 write32((void *)addr, val);
121}
122
123static uint32_t read32p(uintptr_t addr)
124{
125 return read32((void *)addr);
126}
127
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100128static void sfence(void)
129{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100130 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100131}
132
133static inline u16 get_lane_offset(int slot, int rank, int lane)
134{
135 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
136 0x452 * (lane == 8);
137}
138
139static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
140{
141 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
142 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
143}
144
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100145static u32 gav_real(int line, u32 in)
146{
147 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
148 return in;
149}
150
151#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200152
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200153/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100154timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200155
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100156/* OK */
157static u16
158read_500(struct raminfo *info, int channel, u16 addr, int split)
159{
160 u32 val;
161 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200162 MCHBAR32(0x500 + (channel << 10)) = 0;
163 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
164 ;
165 MCHBAR32(0x500 + (channel << 10)) =
166 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
167 + 0xb88 - addr);
168 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
169 ;
170 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100171 return val & ((1 << split) - 1);
172}
173
174/* OK */
175static void
176write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
177 int flag)
178{
179 if (info->last_500_command[channel] == 0x80000000) {
180 info->last_500_command[channel] = 0x40000000;
181 write_500(info, channel, 0, 0xb61, 0, 0);
182 }
Felix Held04be2dd2018-07-29 04:53:22 +0200183 MCHBAR32(0x500 + (channel << 10)) = 0;
184 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
185 ;
186 MCHBAR32(0x504 + (channel << 10)) =
187 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
188 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200189 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200190 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100191}
192
Angel Ponsc10f8b22021-01-15 20:34:51 +0100193static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
194{
195 const u32 val = read_500(info, channel, addr, bits) & and;
196 write_500(info, channel, val | or, addr, bits, 1);
197}
198
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100199static int rw_test(int rank)
200{
201 const u32 mask = 0xf00fc33c;
202 int ok = 0xff;
203 int i;
204 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800205 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100206 sfence();
207 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800208 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209 sfence();
210 for (i = 0; i < 32; i++) {
211 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800212 write32p((rank << 28) | (i << 3), pat);
213 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214 }
215 sfence();
216 for (i = 0; i < 32; i++) {
217 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
218 int j;
219 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800220 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100221 for (j = 0; j < 4; j++)
222 if (((val >> (j * 8)) & 0xff) != pat)
223 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800224 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100225 for (j = 0; j < 4; j++)
226 if (((val >> (j * 8)) & 0xff) != pat)
227 ok &= ~(16 << j);
228 }
229 sfence();
230 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800231 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232 sfence();
233 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800234 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100235
236 return ok;
237}
238
239static void
240program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
241{
242 int lane;
243 for (lane = 0; lane < 8; lane++) {
244 write_500(info, channel,
245 base +
246 info->training.
247 lane_timings[2][channel][slot][rank][lane],
248 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
249 write_500(info, channel,
250 base +
251 info->training.
252 lane_timings[3][channel][slot][rank][lane],
253 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
254 }
255}
256
257static void write_26c(int channel, u16 si)
258{
Felix Held04be2dd2018-07-29 04:53:22 +0200259 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
260 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
261 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100262}
263
Angel Ponsc627dc92020-09-22 17:06:44 +0200264static void toggle_1d0_142_5ff(void)
265{
266 u32 reg32 = gav(read_1d0(0x142, 3));
267 if (reg32 & (1 << 1))
268 write_1d0(0, 0x142, 3, 1);
269
270 MCHBAR8(0x5ff) = 0x0;
271 MCHBAR8(0x5ff) = 0x80;
272 if (reg32 & (1 << 1))
273 write_1d0(0x2, 0x142, 3, 1);
274}
275
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276static u32 get_580(int channel, u8 addr)
277{
278 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200279 toggle_1d0_142_5ff();
Felix Held04be2dd2018-07-29 04:53:22 +0200280 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
281 MCHBAR8_OR(0x580 + (channel << 10), 1);
282 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
283 ;
284 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 return ret;
286}
287
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288#define RANK_SHIFT 28
289#define CHANNEL_SHIFT 10
290
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291static void seq9(struct raminfo *info, int channel, int slot, int rank)
292{
293 int i, lane;
294
295 for (i = 0; i < 2; i++)
296 for (lane = 0; lane < 8; lane++)
297 write_500(info, channel,
298 info->training.lane_timings[i +
299 1][channel][slot]
300 [rank][lane], get_timing_register_addr(lane,
301 i + 1,
302 slot,
303 rank),
304 9, 0);
305
306 write_1d0(1, 0x103, 6, 1);
307 for (lane = 0; lane < 8; lane++)
308 write_500(info, channel,
309 info->training.
310 lane_timings[0][channel][slot][rank][lane],
311 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
312
313 for (i = 0; i < 2; i++) {
314 for (lane = 0; lane < 8; lane++)
315 write_500(info, channel,
316 info->training.lane_timings[i +
317 1][channel][slot]
318 [rank][lane], get_timing_register_addr(lane,
319 i + 1,
320 slot,
321 rank),
322 9, 0);
323 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
324 }
325
Angel Ponsc627dc92020-09-22 17:06:44 +0200326 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100327 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200328
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100329 for (lane = 0; lane < 8; lane++) {
330 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
331 info->training.lane_timings[2][channel][slot][rank][lane] =
332 read_500(info, channel,
333 get_timing_register_addr(lane, 2, slot, rank), 9);
334 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
335 info->training.lane_timings[3][channel][slot][rank][lane] =
336 info->training.lane_timings[2][channel][slot][rank][lane] +
337 0x20;
338 }
339}
340
341static int count_ranks_in_channel(struct raminfo *info, int channel)
342{
343 int slot, rank;
344 int res = 0;
345 for (slot = 0; slot < NUM_SLOTS; slot++)
346 for (rank = 0; rank < NUM_SLOTS; rank++)
347 res += info->populated_ranks[channel][slot][rank];
348 return res;
349}
350
351static void
352config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
353{
354 int add;
355
356 write_1d0(0, 0x178, 7, 1);
357 seq9(info, channel, slot, rank);
358 program_timings(info, 0x80, channel, slot, rank);
359
360 if (channel == 0)
361 add = count_ranks_in_channel(info, 1);
362 else
363 add = 0;
364 if (!s3resume)
365 gav(rw_test(rank + add));
366 program_timings(info, 0x00, channel, slot, rank);
367 if (!s3resume)
368 gav(rw_test(rank + add));
369 if (!s3resume)
370 gav(rw_test(rank + add));
371 write_1d0(0, 0x142, 3, 1);
372 write_1d0(0, 0x103, 6, 1);
373
374 gav(get_580(channel, 0xc | (rank << 5)));
375 gav(read_1d0(0x142, 3));
376
Felix Held04be2dd2018-07-29 04:53:22 +0200377 MCHBAR8(0x5ff) = 0x0;
378 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100379}
380
Angel Ponsc10f8b22021-01-15 20:34:51 +0100381static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100382{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100383 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
384
385 val &= 1;
386 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
387 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100388}
389
390static void set_334(int zero)
391{
392 int j, k, channel;
393 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
394 u32 vd8[2][16];
395
396 for (channel = 0; channel < NUM_CHANNELS; channel++) {
397 for (j = 0; j < 4; j++) {
398 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
399 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
400 u16 c;
401 if ((j == 0 || j == 3) && zero)
402 c = 0;
403 else if (j == 3)
404 c = 0x5f;
405 else
406 c = 0x5f5f;
407
408 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200409 MCHBAR32(0x138 + 8 * k) =
410 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100411 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200412 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100413 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200414 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100415 }
416
Felix Held22ca8cb2018-07-29 05:09:44 +0200417 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
418 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200419 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
420 zero ? 0 : (0x18191819 & lmask);
421 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
422 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
423 zero ? 0 : (a & lmask);
424 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
425 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100426 }
427 }
428
Felix Held04be2dd2018-07-29 04:53:22 +0200429 MCHBAR32_OR(0x130, 1);
430 while (MCHBAR8(0x130) & 1)
431 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100432}
433
Angel Pons244f4552021-01-15 20:41:36 +0100434static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100435{
436 u32 v;
437 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100438 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100439}
440
441static int find_highest_bit_set(u16 val)
442{
443 int i;
444 for (i = 15; i >= 0; i--)
445 if (val & (1 << i))
446 return i;
447 return -1;
448}
449
450static int find_lowest_bit_set32(u32 val)
451{
452 int i;
453 for (i = 0; i < 32; i++)
454 if (val & (1 << i))
455 return i;
456 return -1;
457}
458
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100459enum {
460 DEVICE_TYPE = 2,
461 MODULE_TYPE = 3,
462 DENSITY = 4,
463 RANKS_AND_DQ = 7,
464 MEMORY_BUS_WIDTH = 8,
465 TIMEBASE_DIVIDEND = 10,
466 TIMEBASE_DIVISOR = 11,
467 CYCLETIME = 12,
468
469 CAS_LATENCIES_LSB = 14,
470 CAS_LATENCIES_MSB = 15,
471 CAS_LATENCY_TIME = 16,
472 THERMAL_AND_REFRESH = 31,
473 REFERENCE_RAW_CARD_USED = 62,
474 RANK1_ADDRESS_MAPPING = 63
475};
476
477static void calculate_timings(struct raminfo *info)
478{
Martin Roth468d02c2019-10-23 21:44:42 -0600479 unsigned int cycletime;
480 unsigned int cas_latency_time;
481 unsigned int supported_cas_latencies;
482 unsigned int channel, slot;
483 unsigned int clock_speed_index;
484 unsigned int min_cas_latency;
485 unsigned int cas_latency;
486 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100487
488 /* Find common CAS latency */
489 supported_cas_latencies = 0x3fe;
490 for (channel = 0; channel < NUM_CHANNELS; channel++)
491 for (slot = 0; slot < NUM_SLOTS; slot++)
492 if (info->populated_ranks[channel][slot][0])
493 supported_cas_latencies &=
494 2 *
495 (info->
496 spd[channel][slot][CAS_LATENCIES_LSB] |
497 (info->
498 spd[channel][slot][CAS_LATENCIES_MSB] <<
499 8));
500
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100501 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100502
503 cycletime = min_cycletime[max_clock_index];
504 cas_latency_time = min_cas_latency_time[max_clock_index];
505
506 for (channel = 0; channel < NUM_CHANNELS; channel++)
507 for (slot = 0; slot < NUM_SLOTS; slot++)
508 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600509 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100510 timebase =
511 1000 *
512 info->
513 spd[channel][slot][TIMEBASE_DIVIDEND] /
514 info->spd[channel][slot][TIMEBASE_DIVISOR];
515 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100516 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100517 timebase *
518 info->spd[channel][slot][CYCLETIME]);
519 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100520 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100521 timebase *
522 info->
523 spd[channel][slot][CAS_LATENCY_TIME]);
524 }
Jacob Garber3c193822019-06-10 18:23:32 -0600525 if (cycletime > min_cycletime[0])
526 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100527 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
528 if (cycletime == min_cycletime[clock_speed_index])
529 break;
530 if (cycletime > min_cycletime[clock_speed_index]) {
531 clock_speed_index--;
532 cycletime = min_cycletime[clock_speed_index];
533 break;
534 }
535 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100536 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100537 cas_latency = 0;
538 while (supported_cas_latencies) {
539 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
540 if (cas_latency <= min_cas_latency)
541 break;
542 supported_cas_latencies &=
543 ~(1 << find_highest_bit_set(supported_cas_latencies));
544 }
545
546 if (cas_latency != min_cas_latency && clock_speed_index)
547 clock_speed_index--;
548
549 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
550 die("Couldn't configure DRAM");
551 info->clock_speed_index = clock_speed_index;
552 info->cas_latency = cas_latency;
553}
554
555static void program_base_timings(struct raminfo *info)
556{
Martin Roth468d02c2019-10-23 21:44:42 -0600557 unsigned int channel;
558 unsigned int slot, rank, lane;
559 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100560 int i;
561
562 extended_silicon_revision = info->silicon_revision;
563 if (info->silicon_revision == 0)
564 for (channel = 0; channel < NUM_CHANNELS; channel++)
565 for (slot = 0; slot < NUM_SLOTS; slot++)
566 if ((info->
567 spd[channel][slot][MODULE_TYPE] & 0xF) ==
568 3)
569 extended_silicon_revision = 4;
570
571 for (channel = 0; channel < NUM_CHANNELS; channel++) {
572 for (slot = 0; slot < NUM_SLOTS; slot++)
573 for (rank = 0; rank < NUM_SLOTS; rank++) {
574 int card_timing_2;
575 if (!info->populated_ranks[channel][slot][rank])
576 continue;
577
578 for (lane = 0; lane < 9; lane++) {
579 int tm_reg;
580 int card_timing;
581
582 card_timing = 0;
583 if ((info->
584 spd[channel][slot][MODULE_TYPE] &
585 0xF) == 3) {
586 int reference_card;
587 reference_card =
588 info->
589 spd[channel][slot]
590 [REFERENCE_RAW_CARD_USED] &
591 0x1f;
592 if (reference_card == 3)
593 card_timing =
594 u16_ffd1188[0][lane]
595 [info->
596 clock_speed_index];
597 if (reference_card == 5)
598 card_timing =
599 u16_ffd1188[1][lane]
600 [info->
601 clock_speed_index];
602 }
603
604 info->training.
605 lane_timings[0][channel][slot][rank]
606 [lane] =
607 u8_FFFD1218[info->
608 clock_speed_index];
609 info->training.
610 lane_timings[1][channel][slot][rank]
611 [lane] = 256;
612
613 for (tm_reg = 2; tm_reg < 4; tm_reg++)
614 info->training.
615 lane_timings[tm_reg]
616 [channel][slot][rank][lane]
617 =
618 u8_FFFD1240[channel]
619 [extended_silicon_revision]
620 [lane][2 * slot +
621 rank][info->
622 clock_speed_index]
623 + info->max4048[channel]
624 +
625 u8_FFFD0C78[channel]
626 [extended_silicon_revision]
627 [info->
628 mode4030[channel]][slot]
629 [rank][info->
630 clock_speed_index]
631 + card_timing;
632 for (tm_reg = 0; tm_reg < 4; tm_reg++)
633 write_500(info, channel,
634 info->training.
635 lane_timings[tm_reg]
636 [channel][slot][rank]
637 [lane],
638 get_timing_register_addr
639 (lane, tm_reg, slot,
640 rank), 9, 0);
641 }
642
643 card_timing_2 = 0;
644 if (!(extended_silicon_revision != 4
645 || (info->
646 populated_ranks_mask[channel] & 5) ==
647 5)) {
648 if ((info->
649 spd[channel][slot]
650 [REFERENCE_RAW_CARD_USED] & 0x1F)
651 == 3)
652 card_timing_2 =
653 u16_FFFE0EB8[0][info->
654 clock_speed_index];
655 if ((info->
656 spd[channel][slot]
657 [REFERENCE_RAW_CARD_USED] & 0x1F)
658 == 5)
659 card_timing_2 =
660 u16_FFFE0EB8[1][info->
661 clock_speed_index];
662 }
663
664 for (i = 0; i < 3; i++)
665 write_500(info, channel,
666 (card_timing_2 +
667 info->max4048[channel]
668 +
669 u8_FFFD0EF8[channel]
670 [extended_silicon_revision]
671 [info->
672 mode4030[channel]][info->
673 clock_speed_index]),
674 u16_fffd0c50[i][slot][rank],
675 8, 1);
676 write_500(info, channel,
677 (info->max4048[channel] +
678 u8_FFFD0C78[channel]
679 [extended_silicon_revision][info->
680 mode4030
681 [channel]]
682 [slot][rank][info->
683 clock_speed_index]),
684 u16_fffd0c70[slot][rank], 7, 1);
685 }
686 if (!info->populated_ranks_mask[channel])
687 continue;
688 for (i = 0; i < 3; i++)
689 write_500(info, channel,
690 (info->max4048[channel] +
691 info->avg4044[channel]
692 +
693 u8_FFFD17E0[channel]
694 [extended_silicon_revision][info->
695 mode4030
696 [channel]][info->
697 clock_speed_index]),
698 u16_fffd0c68[i], 8, 1);
699 }
700}
701
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100702/* The time of clock cycle in ps. */
703static unsigned int cycle_ps(struct raminfo *info)
704{
705 return 2 * halfcycle_ps(info);
706}
707
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100708/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600709static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100710{
711 return 100 * frequency_11(info) / 9;
712}
713
Martin Roth468d02c2019-10-23 21:44:42 -0600714static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100715{
716 return (frequency_11(info) * 2) * ps / 900000;
717}
718
Martin Roth468d02c2019-10-23 21:44:42 -0600719static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100720{
721 return (frequency_11(info)) * ns / 900;
722}
723
724static void compute_derived_timings(struct raminfo *info)
725{
Martin Roth468d02c2019-10-23 21:44:42 -0600726 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100727 int extended_silicon_revision;
728 int some_delay_1_ps;
729 int some_delay_2_ps;
730 int some_delay_2_halfcycles_ceil;
731 int some_delay_2_halfcycles_floor;
732 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100733 int some_delay_3_ps_rounded;
734 int some_delay_1_cycle_ceil;
735 int some_delay_1_cycle_floor;
736
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100737 some_delay_3_ps_rounded = 0;
738 extended_silicon_revision = info->silicon_revision;
739 if (!info->silicon_revision)
740 for (channel = 0; channel < NUM_CHANNELS; channel++)
741 for (slot = 0; slot < NUM_SLOTS; slot++)
742 if ((info->
743 spd[channel][slot][MODULE_TYPE] & 0xF) ==
744 3)
745 extended_silicon_revision = 4;
746 if (info->board_lane_delay[7] < 5)
747 info->board_lane_delay[7] = 5;
748 info->revision_flag_1 = 2;
749 if (info->silicon_revision == 2 || info->silicon_revision == 3)
750 info->revision_flag_1 = 0;
751 if (info->revision < 16)
752 info->revision_flag_1 = 0;
753
754 if (info->revision < 8)
755 info->revision_flag_1 = 0;
756 if (info->revision >= 8 && (info->silicon_revision == 0
757 || info->silicon_revision == 1))
758 some_delay_2_ps = 735;
759 else
760 some_delay_2_ps = 750;
761
762 if (info->revision >= 0x10 && (info->silicon_revision == 0
763 || info->silicon_revision == 1))
764 some_delay_1_ps = 3929;
765 else
766 some_delay_1_ps = 3490;
767
768 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
769 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
770 if (some_delay_1_ps % cycle_ps(info))
771 some_delay_1_cycle_ceil++;
772 else
773 some_delay_1_cycle_floor--;
774 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
775 if (info->revision_flag_1)
776 some_delay_2_ps = halfcycle_ps(info) >> 6;
777 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100778 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100779 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
780 375;
781 some_delay_3_ps =
782 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
783 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200784 if (some_delay_3_ps >= 150) {
785 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200787 some_delay_3_ps_rounded =
788 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
789 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100790 }
791 some_delay_2_halfcycles_ceil =
792 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
793 2 * (some_delay_1_cycle_ceil - 1);
794 if (info->revision_flag_1 && some_delay_3_ps < 150)
795 some_delay_2_halfcycles_ceil++;
796 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
797 if (info->revision < 0x10)
798 some_delay_2_halfcycles_floor =
799 some_delay_2_halfcycles_ceil - 1;
800 if (!info->revision_flag_1)
801 some_delay_2_halfcycles_floor++;
802 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
803 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
804 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
805 || (info->populated_ranks[1][0][0]
806 && info->populated_ranks[1][1][0]))
807 info->max_slots_used_in_channel = 2;
808 else
809 info->max_slots_used_in_channel = 1;
810 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200811 MCHBAR32(0x244 + (channel << 10)) =
812 ((info->revision < 8) ? 1 : 0x200) |
813 ((2 - info->max_slots_used_in_channel) << 17) |
814 (channel << 21) |
815 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100816 if (info->max_slots_used_in_channel == 1) {
817 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
818 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
819 } else {
820 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 */
821 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
822 || (count_ranks_in_channel(info, 1) ==
823 2)) ? 2 : 3;
824 }
825 for (channel = 0; channel < NUM_CHANNELS; channel++) {
826 int max_of_unk;
827 int min_of_unk_2;
828
829 int i, count;
830 int sum;
831
832 if (!info->populated_ranks_mask[channel])
833 continue;
834
835 max_of_unk = 0;
836 min_of_unk_2 = 32767;
837
838 sum = 0;
839 count = 0;
840 for (i = 0; i < 3; i++) {
841 int unk1;
842 if (info->revision < 8)
843 unk1 =
844 u8_FFFD1891[0][channel][info->
845 clock_speed_index]
846 [i];
847 else if (!
848 (info->revision >= 0x10
849 || info->revision_flag_1))
850 unk1 =
851 u8_FFFD1891[1][channel][info->
852 clock_speed_index]
853 [i];
854 else
855 unk1 = 0;
856 for (slot = 0; slot < NUM_SLOTS; slot++)
857 for (rank = 0; rank < NUM_RANKS; rank++) {
858 int a = 0;
859 int b = 0;
860
861 if (!info->
862 populated_ranks[channel][slot]
863 [rank])
864 continue;
865 if (extended_silicon_revision == 4
866 && (info->
867 populated_ranks_mask[channel] &
868 5) != 5) {
869 if ((info->
870 spd[channel][slot]
871 [REFERENCE_RAW_CARD_USED] &
872 0x1F) == 3) {
873 a = u16_ffd1178[0]
874 [info->
875 clock_speed_index];
876 b = u16_fe0eb8[0][info->
877 clock_speed_index];
878 } else
879 if ((info->
880 spd[channel][slot]
881 [REFERENCE_RAW_CARD_USED]
882 & 0x1F) == 5) {
883 a = u16_ffd1178[1]
884 [info->
885 clock_speed_index];
886 b = u16_fe0eb8[1][info->
887 clock_speed_index];
888 }
889 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100890 min_of_unk_2 = MIN(min_of_unk_2, a);
891 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 if (rank == 0) {
893 sum += a;
894 count++;
895 }
896 {
897 int t;
898 t = b +
899 u8_FFFD0EF8[channel]
900 [extended_silicon_revision]
901 [info->
902 mode4030[channel]][info->
903 clock_speed_index];
904 if (unk1 >= t)
905 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100906 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100907 unk1 - t);
908 }
909 }
910 {
911 int t =
912 u8_FFFD17E0[channel]
913 [extended_silicon_revision][info->
914 mode4030
915 [channel]]
916 [info->clock_speed_index] + min_of_unk_2;
917 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100918 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100919 }
920 }
921
Jacob Garber64fb4a32019-06-10 17:29:18 -0600922 if (count == 0)
923 die("No memory ranks found for channel %u\n", channel);
924
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100925 info->avg4044[channel] = sum / count;
926 info->max4048[channel] = max_of_unk;
927 }
928}
929
930static void jedec_read(struct raminfo *info,
931 int channel, int slot, int rank,
932 int total_rank, u8 addr3, unsigned int value)
933{
934 /* Handle mirrored mapping. */
935 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +0200936 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
937 ((addr3 >> 1) & 0x10);
938 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
939 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100940
941 /* Handle mirrored mapping. */
942 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
943 value =
944 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
945 << 1);
946
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800947 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100948
Felix Held04be2dd2018-07-29 04:53:22 +0200949 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
950 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100951
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800952 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100953}
954
955enum {
956 MR1_RZQ12 = 512,
957 MR1_RZQ2 = 64,
958 MR1_RZQ4 = 4,
959 MR1_ODS34OHM = 2
960};
961
962enum {
963 MR0_BT_INTERLEAVED = 8,
964 MR0_DLL_RESET_ON = 256
965};
966
967enum {
968 MR2_RTT_WR_DISABLED = 0,
969 MR2_RZQ2 = 1 << 10
970};
971
972static void jedec_init(struct raminfo *info)
973{
974 int write_recovery;
975 int channel, slot, rank;
976 int total_rank;
977 int dll_on;
978 int self_refresh_temperature;
979 int auto_self_refresh;
980
981 auto_self_refresh = 1;
982 self_refresh_temperature = 1;
983 if (info->board_lane_delay[3] <= 10) {
984 if (info->board_lane_delay[3] <= 8)
985 write_recovery = info->board_lane_delay[3] - 4;
986 else
987 write_recovery = 5;
988 } else {
989 write_recovery = 6;
990 }
991 FOR_POPULATED_RANKS {
992 auto_self_refresh &=
993 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
994 self_refresh_temperature &=
995 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
996 }
997 if (auto_self_refresh == 1)
998 self_refresh_temperature = 0;
999
1000 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1001 || (info->populated_ranks[0][0][0]
1002 && info->populated_ranks[0][1][0])
1003 || (info->populated_ranks[1][0][0]
1004 && info->populated_ranks[1][1][0]));
1005
1006 total_rank = 0;
1007
1008 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1009 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1010 int rzq_reg58e;
1011
1012 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1013 rzq_reg58e = 64;
1014 rtt = MR1_RZQ2;
1015 if (info->clock_speed_index != 0) {
1016 rzq_reg58e = 4;
1017 if (info->populated_ranks_mask[channel] == 3)
1018 rtt = MR1_RZQ4;
1019 }
1020 } else {
1021 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1022 rtt = MR1_RZQ12;
1023 rzq_reg58e = 64;
1024 rtt_wr = MR2_RZQ2;
1025 } else {
1026 rzq_reg58e = 4;
1027 rtt = MR1_RZQ4;
1028 }
1029 }
1030
Felix Held04be2dd2018-07-29 04:53:22 +02001031 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1032 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1033 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1034 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1035 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001036
1037 for (slot = 0; slot < NUM_SLOTS; slot++)
1038 for (rank = 0; rank < NUM_RANKS; rank++)
1039 if (info->populated_ranks[channel][slot][rank]) {
1040 jedec_read(info, channel, slot, rank,
1041 total_rank, 0x28,
1042 rtt_wr | (info->
1043 clock_speed_index
1044 << 3)
1045 | (auto_self_refresh << 6) |
1046 (self_refresh_temperature <<
1047 7));
1048 jedec_read(info, channel, slot, rank,
1049 total_rank, 0x38, 0);
1050 jedec_read(info, channel, slot, rank,
1051 total_rank, 0x18,
1052 rtt | MR1_ODS34OHM);
1053 jedec_read(info, channel, slot, rank,
1054 total_rank, 6,
1055 (dll_on << 12) |
1056 (write_recovery << 9)
1057 | ((info->cas_latency - 4) <<
1058 4) | MR0_BT_INTERLEAVED |
1059 MR0_DLL_RESET_ON);
1060 total_rank++;
1061 }
1062 }
1063}
1064
1065static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1066{
Martin Roth468d02c2019-10-23 21:44:42 -06001067 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001068 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1069 unsigned int channel_0_non_interleaved;
1070
1071 FOR_ALL_RANKS {
1072 if (info->populated_ranks[channel][slot][rank]) {
1073 total_mb[channel] +=
1074 pre_jedec ? 256 : (256 << info->
1075 density[channel][slot] >> info->
1076 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001077 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1078 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1079 (info->is_x16_module[channel][slot] |
1080 ((info->density[channel][slot] + 1) << 1))) |
1081 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001082 }
Felix Held04be2dd2018-07-29 04:53:22 +02001083 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1084 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001085 }
1086
1087 info->total_memory_mb = total_mb[0] + total_mb[1];
1088
1089 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001090 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001091 info->non_interleaved_part_mb =
1092 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1093 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001094 MCHBAR32(0x100) = channel_0_non_interleaved |
1095 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001096 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001097 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001098}
1099
1100static void program_board_delay(struct raminfo *info)
1101{
1102 int cas_latency_shift;
1103 int some_delay_ns;
1104 int some_delay_3_half_cycles;
1105
Martin Roth468d02c2019-10-23 21:44:42 -06001106 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001107 int high_multiplier;
1108 int lane_3_delay;
1109 int cas_latency_derived;
1110
1111 high_multiplier = 0;
1112 some_delay_ns = 200;
1113 some_delay_3_half_cycles = 4;
1114 cas_latency_shift = info->silicon_revision == 0
1115 || info->silicon_revision == 1 ? 1 : 0;
1116 if (info->revision < 8) {
1117 some_delay_ns = 600;
1118 cas_latency_shift = 0;
1119 }
1120 {
1121 int speed_bit;
1122 speed_bit =
1123 ((info->clock_speed_index > 1
1124 || (info->silicon_revision != 2
1125 && info->silicon_revision != 3))) ^ (info->revision >=
1126 0x10);
1127 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1128 3, 1);
1129 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1130 3, 1);
1131 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1132 && (info->silicon_revision == 2
1133 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001134 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001135 }
Felix Held04be2dd2018-07-29 04:53:22 +02001136 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1137 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001138
Felix Held04be2dd2018-07-29 04:53:22 +02001139 MCHBAR8(0x124) = info->board_lane_delay[4] +
1140 ((frequency_01(info) + 999) / 1000);
1141 MCHBAR16(0x125) = 0x1360;
1142 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001143 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001144 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001145 high_multiplier = 1;
1146 some_delay_2_half_cycles = ps_to_halfcycles(info,
1147 ((3 *
1148 fsbcycle_ps(info))
1149 >> 1) +
1150 (halfcycle_ps(info)
1151 *
1152 reg178_min[info->
1153 clock_speed_index]
1154 >> 6)
1155 +
1156 4 *
1157 halfcycle_ps(info)
1158 + 2230);
1159 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001160 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 (frequency_11(info) * 2) * (28 -
1162 some_delay_2_half_cycles) /
1163 (frequency_11(info) * 2 -
1164 4 * (info->fsb_frequency))) >> 3, 7);
1165 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001166 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 some_delay_3_half_cycles = 3;
1168 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001169 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1170 MCHBAR32(0x224 + (channel << 10)) =
1171 (info->max_slots_used_in_channel - 1) |
1172 ((info->cas_latency - 5 - info->clock_speed_index)
1173 << 21) | ((info->max_slots_used_in_channel +
1174 info->cas_latency - cas_latency_shift - 4) << 16) |
1175 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1176 ((info->cas_latency - info->clock_speed_index +
1177 info->max_slots_used_in_channel - 6) << 8);
1178 MCHBAR32(0x228 + (channel << 10)) =
1179 info->max_slots_used_in_channel;
1180 MCHBAR8(0x239 + (channel << 10)) = 32;
1181 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1182 (some_delay_3_half_cycles << 25) | 0x840000;
1183 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1184 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1185 MCHBAR32(0x24c + (channel << 10)) =
1186 ((!!info->clock_speed_index) << 17) |
1187 (((2 + info->clock_speed_index -
1188 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189
Felix Held04be2dd2018-07-29 04:53:22 +02001190 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1191 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1192 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001193
1194 write_500(info, channel,
1195 ((!info->populated_ranks[channel][1][1])
1196 | (!info->populated_ranks[channel][1][0] << 1)
1197 | (!info->populated_ranks[channel][0][1] << 2)
1198 | (!info->populated_ranks[channel][0][0] << 3)),
1199 0x4c9, 4, 1);
1200 }
1201
Felix Held22ca8cb2018-07-29 05:09:44 +02001202 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001203 {
1204 u8 freq_divisor = 2;
1205 if (info->fsb_frequency == frequency_11(info))
1206 freq_divisor = 3;
1207 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1208 freq_divisor = 1;
1209 else
1210 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001211 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 }
1213
1214 if (info->board_lane_delay[3] <= 10) {
1215 if (info->board_lane_delay[3] <= 8)
1216 lane_3_delay = info->board_lane_delay[3];
1217 else
1218 lane_3_delay = 10;
1219 } else {
1220 lane_3_delay = 12;
1221 }
1222 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1223 if (info->clock_speed_index > 1)
1224 cas_latency_derived++;
1225 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR32(0x240 + (channel << 10)) =
1227 ((info->clock_speed_index == 0) * 0x11000) |
1228 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1229 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1231 0x609, 6, 1);
1232 write_500(info, channel,
1233 info->clock_speed_index + 2 * info->cas_latency - 7,
1234 0x601, 6, 1);
1235
Felix Held04be2dd2018-07-29 04:53:22 +02001236 MCHBAR32(0x250 + (channel << 10)) =
1237 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1238 (info->board_lane_delay[7] << 2) |
1239 (info->board_lane_delay[4] << 16) |
1240 (info->board_lane_delay[1] << 25) |
1241 (info->board_lane_delay[1] << 29) | 1;
1242 MCHBAR32(0x254 + (channel << 10)) =
1243 (info->board_lane_delay[1] >> 3) |
1244 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1245 0x80 | (info->board_lane_delay[6] << 1) |
1246 (info->board_lane_delay[2] << 28) |
1247 (cas_latency_derived << 16) | 0x4700000;
1248 MCHBAR32(0x258 + (channel << 10)) =
1249 ((info->board_lane_delay[5] + info->clock_speed_index +
1250 9) << 12) | ((info->clock_speed_index -
1251 info->cas_latency + 12) << 8) |
1252 (info->board_lane_delay[2] << 17) |
1253 (info->board_lane_delay[4] << 24) | 0x47;
1254 MCHBAR32(0x25c + (channel << 10)) =
1255 (info->board_lane_delay[1] << 1) |
1256 (info->board_lane_delay[0] << 8) | 0x1da50000;
1257 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1258 MCHBAR8(0x5f8 + (channel << 10)) =
1259 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 }
1261
1262 program_modules_memory_map(info, 1);
1263
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001264 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001265 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1266 MCHBAR16_OR(0x612, 0x100);
1267 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001268 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001269 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001270 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001271 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 }
1273}
1274
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001275#define DEFAULT_PCI_MMIO_SIZE 2048
1276#define HOST_BRIDGE PCI_DEVFN(0, 0)
1277
1278static unsigned int get_mmio_size(void)
1279{
1280 const struct device *dev;
Angel Pons95de2312020-02-17 13:08:53 +01001281 const struct northbridge_intel_ironlake_config *cfg = NULL;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001282
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001283 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001284 if (dev)
1285 cfg = dev->chip_info;
1286
1287 /* If this is zero, it just means devicetree.cb didn't set it */
1288 if (!cfg || cfg->pci_mmio_size == 0)
1289 return DEFAULT_PCI_MMIO_SIZE;
1290 else
1291 return cfg->pci_mmio_size;
1292}
1293
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294static void program_total_memory_map(struct raminfo *info)
1295{
Angel Pons9333b742020-07-22 16:04:15 +02001296 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001298 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001299 unsigned int uma_base_igd;
1300 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001301 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001302 int memory_remap;
1303 unsigned int memory_map[8];
1304 int i;
1305 unsigned int current_limit;
1306 unsigned int tseg_base;
1307 int uma_size_igd = 0, uma_size_gtt = 0;
1308
1309 memset(memory_map, 0, sizeof(memory_map));
1310
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001311 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001312 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001313 gav(t);
1314 const int uma_sizes_gtt[16] =
1315 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1316 /* Igd memory */
1317 const int uma_sizes_igd[16] = {
1318 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1319 256, 512
1320 };
1321
1322 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1323 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1324 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001325
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001326 mmio_size = get_mmio_size();
1327
Angel Pons9333b742020-07-22 16:04:15 +02001328 tom = info->total_memory_mb;
1329 if (tom == 4096)
1330 tom = 4032;
1331 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1332 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1333 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001334 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001335 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001336 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001337 remap_base = MAX(4096, touud);
1338 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 }
Angel Pons9333b742020-07-22 16:04:15 +02001340 if (touud > 4096)
1341 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001342 quickpath_reserved = 0;
1343
Angel Pons3ab19b32020-07-22 16:29:54 +02001344 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001345
Jacob Garber975a7e32019-06-10 16:32:47 -06001346 gav(t);
1347
1348 if (t & 0x800) {
1349 u32 shift = t >> 20;
1350 if (shift == 0)
1351 die("Quickpath value is 0\n");
1352 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001354
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001355 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001356 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001357
Angel Pons9333b742020-07-22 16:04:15 +02001358 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 uma_base_gtt = uma_base_igd - uma_size_gtt;
1360 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1361 if (!memory_remap)
1362 tseg_base -= quickpath_reserved;
1363 tseg_base = ALIGN_DOWN(tseg_base, 8);
1364
Angel Pons16fe1e02020-07-22 16:12:33 +02001365 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1366 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001367 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001368 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1369 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001370 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001371 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001372
1373 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001374 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1375 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001376 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001377 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378
1379 current_limit = 0;
1380 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1381 memory_map[1] = 4096;
1382 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001383 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001384 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001385 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1386 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001387 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001388 }
1389}
1390
1391static void collect_system_info(struct raminfo *info)
1392{
1393 u32 capid0[3];
1394 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001395 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001396
Angel Ponsb600d412021-01-16 16:33:48 +01001397 for (i = 0; i < 3; i++) {
1398 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1399 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1400 }
1401 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1402 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1403 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1404
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1406
1407 if ((capid0[1] >> 11) & 1)
1408 info->uma_enabled = 0;
1409 else
1410 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001411 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1413 info->silicon_revision = 0;
1414
1415 if (capid0[2] & 2) {
1416 info->silicon_revision = 0;
1417 info->max_supported_clock_speed_index = 2;
1418 for (channel = 0; channel < NUM_CHANNELS; channel++)
1419 if (info->populated_ranks[channel][0][0]
1420 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1421 3) {
1422 info->silicon_revision = 2;
1423 info->max_supported_clock_speed_index = 1;
1424 }
1425 } else {
1426 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1427 case 1:
1428 case 2:
1429 info->silicon_revision = 3;
1430 break;
1431 case 3:
1432 info->silicon_revision = 0;
1433 break;
1434 case 0:
1435 info->silicon_revision = 2;
1436 break;
1437 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001438 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439 case 0x40:
1440 info->silicon_revision = 0;
1441 break;
1442 case 0x48:
1443 info->silicon_revision = 1;
1444 break;
1445 }
1446 }
1447}
1448
1449static void write_training_data(struct raminfo *info)
1450{
1451 int tm, channel, slot, rank, lane;
1452 if (info->revision < 8)
1453 return;
1454
1455 for (tm = 0; tm < 4; tm++)
1456 for (channel = 0; channel < NUM_CHANNELS; channel++)
1457 for (slot = 0; slot < NUM_SLOTS; slot++)
1458 for (rank = 0; rank < NUM_RANKS; rank++)
1459 for (lane = 0; lane < 9; lane++)
1460 write_500(info, channel,
1461 info->
1462 cached_training->
1463 lane_timings[tm]
1464 [channel][slot][rank]
1465 [lane],
1466 get_timing_register_addr
1467 (lane, tm, slot,
1468 rank), 9, 0);
1469 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1470 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1471}
1472
1473static void dump_timings(struct raminfo *info)
1474{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001475 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001476 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001478 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001479 slot, rank);
1480 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001481 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001482 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001483 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001484 read_500(info, channel,
1485 get_timing_register_addr
1486 (lane, i, slot, rank),
1487 9),
1488 info->training.
1489 lane_timings[i][channel][slot][rank]
1490 [lane]);
1491 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001492 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001493 }
1494 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001495 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001496 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001497 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499}
1500
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001501/* Read timings and other registers that need to be restored verbatim and
1502 put them to CBMEM.
1503 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001504static void save_timings(struct raminfo *info)
1505{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507 int channel, slot, rank, lane, i;
1508
1509 train = info->training;
1510 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1511 for (i = 0; i < 4; i++)
1512 train.lane_timings[i][channel][slot][rank][lane] =
1513 read_500(info, channel,
1514 get_timing_register_addr(lane, i, slot,
1515 rank), 9);
1516 train.reg_178 = read_1d0(0x178, 7);
1517 train.reg_10b = read_1d0(0x10b, 6);
1518
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001519 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1520 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001521 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001522 train.reg274265[channel][0] = reg32 >> 16;
1523 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001524 train.reg274265[channel][2] =
1525 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001526 }
Felix Held04be2dd2018-07-29 04:53:22 +02001527 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1528 train.reg_6dc = MCHBAR32(0x6dc);
1529 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001530
Arthur Heymansb3282092019-04-14 17:53:28 +02001531 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1532 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001533
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001534 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001535 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1536 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001537}
1538
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001539static const struct ram_training *get_cached_training(void)
1540{
Shelley Chenad9cd682020-07-23 16:10:52 -07001541 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1542 MRC_CACHE_VERSION,
1543 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001544}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001545
1546/* FIXME: add timeout. */
1547static void wait_heci_ready(void)
1548{
Felix Held04be2dd2018-07-29 04:53:22 +02001549 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1550 ;
Angel Ponseb537932020-09-14 19:18:11 +02001551
1552 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001553}
1554
1555/* FIXME: add timeout. */
1556static void wait_heci_cb_avail(int len)
1557{
1558 union {
1559 struct mei_csr csr;
1560 u32 raw;
1561 } csr;
1562
Felix Held22ca8cb2018-07-29 05:09:44 +02001563 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1564 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001565
Angel Ponseb537932020-09-14 19:18:11 +02001566 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001567 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001568 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1569 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570}
1571
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001572static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001573{
1574 int len = (head->length + 3) / 4;
1575 int i;
1576
1577 wait_heci_cb_avail(len + 1);
1578
1579 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001580 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001582 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001584 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1585 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586}
1587
Angel Ponseb537932020-09-14 19:18:11 +02001588static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589{
1590 struct mei_header head;
1591 int maxlen;
1592
1593 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001594 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001595
1596 while (len) {
1597 int cur = len;
1598 if (cur > maxlen) {
1599 cur = maxlen;
1600 head.is_complete = 0;
1601 } else
1602 head.is_complete = 1;
1603 head.length = cur;
1604 head.reserved = 0;
1605 head.client_address = clientaddress;
1606 head.host_address = hostaddress;
1607 send_heci_packet(&head, (u32 *) msg);
1608 len -= cur;
1609 msg += cur;
1610 }
1611}
1612
1613/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001614static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615{
1616 union {
1617 struct mei_csr csr;
1618 u32 raw;
1619 } csr;
1620 int i = 0;
1621
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001622 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001623 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001624 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001625 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1626
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001627 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001629 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001630 *packet_size = 0;
1631 return 0;
1632 }
Angel Ponseb537932020-09-14 19:18:11 +02001633 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634 *packet_size = 0;
1635 return -1;
1636 }
1637
Angel Ponseb537932020-09-14 19:18:11 +02001638 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001639 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001640 } while (((head->length + 3) >> 2) >
1641 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001642
1643 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001644 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001645 *packet_size = head->length;
1646 if (!csr.csr.ready)
1647 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001648 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649 return 0;
1650}
1651
1652/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001653static int recv_heci_message(u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001654{
1655 struct mei_header head;
1656 int current_position;
1657
1658 current_position = 0;
1659 while (1) {
1660 u32 current_size;
1661 current_size = *message_size - current_position;
1662 if (recv_heci_packet
Angel Pons86907462020-09-14 18:48:59 +02001663 (&head, message + (current_position >> 2),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664 &current_size) == -1)
1665 break;
1666 if (!current_size)
1667 break;
1668 current_position += current_size;
1669 if (head.is_complete) {
1670 *message_size = current_position;
1671 return 0;
1672 }
1673
1674 if (current_position >= *message_size)
1675 break;
1676 }
1677 *message_size = 0;
1678 return -1;
1679}
1680
Angel Pons55f11e22020-09-14 19:06:53 +02001681static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001682{
Patrick Rudolpha1ef2132020-09-08 17:23:04 +02001683 volatile struct uma_reply {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001684 u8 group_id;
1685 u8 command;
1686 u8 reserved;
1687 u8 result;
1688 u8 field2;
1689 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001690 } __packed reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001691
1692 /* FIXME: recv_heci_message() does not always initialize 'reply' */
1693 reply.command = 0;
1694
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695 struct uma_message {
1696 u8 group_id;
1697 u8 cmd;
1698 u8 reserved;
1699 u8 result;
1700 u32 c2;
1701 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001702 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001703 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001704 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001705 .group_id = 0,
1706 .cmd = MKHI_SET_UMA,
1707 .reserved = 0,
1708 .result = 0,
1709 .c2 = 0x82,
1710 .heci_uma_addr = heci_uma_addr,
1711 .heci_uma_size = heci_uma_size,
1712 .c3 = 0,
1713 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714 u32 reply_size;
1715
Angel Ponseb537932020-09-14 19:18:11 +02001716 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717
1718 reply_size = sizeof(reply);
Angel Ponseb537932020-09-14 19:18:11 +02001719 if (recv_heci_message((u32 *) &reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001720 return;
1721
1722 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1723 die("HECI init failed\n");
1724}
1725
1726static void setup_heci_uma(struct raminfo *info)
1727{
Angel Pons298d34d2020-09-14 18:58:53 +02001728 if (!info->memory_reserved_for_heci_mb && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729 return;
1730
Angel Pons36592bf2020-09-14 18:52:44 +02001731 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001733 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 info->memory_reserved_for_heci_mb)) << 20;
1735
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001736 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001737 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001738 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001739 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001740 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001741 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001742 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001743 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001744 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001745 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746
Angel Ponsee7fb342021-01-28 14:11:55 +01001747 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001748 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001749
Angel Ponsee7fb342021-01-28 14:11:55 +01001750 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001751 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001752 }
1753
Felix Held04be2dd2018-07-29 04:53:22 +02001754 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755
Angel Pons55f11e22020-09-14 19:06:53 +02001756 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001758 pci_write_config32(HECIDEV, 0x10, 0x0);
1759 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760}
1761
1762static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1763{
1764 int ranks_in_channel;
1765 ranks_in_channel = info->populated_ranks[channel][0][0]
1766 + info->populated_ranks[channel][0][1]
1767 + info->populated_ranks[channel][1][0]
1768 + info->populated_ranks[channel][1][1];
1769
1770 /* empty channel */
1771 if (ranks_in_channel == 0)
1772 return 1;
1773
1774 if (ranks_in_channel != ranks)
1775 return 0;
1776 /* single slot */
1777 if (info->populated_ranks[channel][0][0] !=
1778 info->populated_ranks[channel][1][0])
1779 return 1;
1780 if (info->populated_ranks[channel][0][1] !=
1781 info->populated_ranks[channel][1][1])
1782 return 1;
1783 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1784 return 0;
1785 if (info->density[channel][0] != info->density[channel][1])
1786 return 0;
1787 return 1;
1788}
1789
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001790static void read_4090(struct raminfo *info)
1791{
1792 int i, channel, slot, rank, lane;
1793 for (i = 0; i < 2; i++)
1794 for (slot = 0; slot < NUM_SLOTS; slot++)
1795 for (rank = 0; rank < NUM_RANKS; rank++)
1796 for (lane = 0; lane < 9; lane++)
1797 info->training.
1798 lane_timings[0][i][slot][rank][lane]
1799 = 32;
1800
1801 for (i = 1; i < 4; i++)
1802 for (channel = 0; channel < NUM_CHANNELS; channel++)
1803 for (slot = 0; slot < NUM_SLOTS; slot++)
1804 for (rank = 0; rank < NUM_RANKS; rank++)
1805 for (lane = 0; lane < 9; lane++) {
1806 info->training.
1807 lane_timings[i][channel]
1808 [slot][rank][lane] =
1809 read_500(info, channel,
1810 get_timing_register_addr
1811 (lane, i, slot,
1812 rank), 9)
1813 + (i == 1) * 11; // !!!!
1814 }
1815
1816}
1817
1818static u32 get_etalon2(int flip, u32 addr)
1819{
1820 const u16 invmask[] = {
1821 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1822 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1823 };
1824 u32 ret;
1825 u32 comp4 = addr / 480;
1826 addr %= 480;
1827 u32 comp1 = addr & 0xf;
1828 u32 comp2 = (addr >> 4) & 1;
1829 u32 comp3 = addr >> 5;
1830
1831 if (comp4)
1832 ret = 0x1010101 << (comp4 - 1);
1833 else
1834 ret = 0;
1835 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1836 ret = ~ret;
1837
1838 return ret;
1839}
1840
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001841static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842{
1843 msr_t msr = {.lo = 0, .hi = 0 };
1844
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001845 wrmsr(MTRR_PHYS_BASE(3), msr);
1846 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847}
1848
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001849static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001850{
1851 msr_t msr;
1852 msr.lo = base | MTRR_TYPE_WRPROT;
1853 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001854 wrmsr(MTRR_PHYS_BASE(3), msr);
1855 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001856 & 0xffffffff);
1857 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001858 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859}
1860
1861static void flush_cache(u32 start, u32 size)
1862{
1863 u32 end;
1864 u32 addr;
1865
1866 end = start + (ALIGN_DOWN(size + 4096, 4096));
1867 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001868 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869}
1870
1871static void clear_errors(void)
1872{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001873 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001874}
1875
1876static void write_testing(struct raminfo *info, int totalrank, int flip)
1877{
1878 int nwrites = 0;
1879 /* in 8-byte units. */
1880 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001881 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001882
Patrick Rudolph819c2062019-11-29 19:27:37 +01001883 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001884 for (offset = 0; offset < 9 * 480; offset += 2) {
1885 write32(base + offset * 8, get_etalon2(flip, offset));
1886 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1887 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1888 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1889 nwrites += 4;
1890 if (nwrites >= 320) {
1891 clear_errors();
1892 nwrites = 0;
1893 }
1894 }
1895}
1896
1897static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1898{
1899 u8 failmask = 0;
1900 int i;
1901 int comp1, comp2, comp3;
1902 u32 failxor[2] = { 0, 0 };
1903
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001904 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001905
1906 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1907 for (comp1 = 0; comp1 < 4; comp1++)
1908 for (comp2 = 0; comp2 < 60; comp2++) {
1909 u32 re[4];
1910 u32 curroffset =
1911 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1912 read128((total_rank << 28) | (curroffset << 3),
1913 (u64 *) re);
1914 failxor[0] |=
1915 get_etalon2(flip, curroffset) ^ re[0];
1916 failxor[1] |=
1917 get_etalon2(flip, curroffset) ^ re[1];
1918 failxor[0] |=
1919 get_etalon2(flip, curroffset | 1) ^ re[2];
1920 failxor[1] |=
1921 get_etalon2(flip, curroffset | 1) ^ re[3];
1922 }
1923 for (i = 0; i < 8; i++)
1924 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1925 failmask |= 1 << i;
1926 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001927 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001928 flush_cache((total_rank << 28), 1728 * 5 * 4);
1929 return failmask;
1930}
1931
1932const u32 seed1[0x18] = {
1933 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1934 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1935 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1936 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1937 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1938 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1939};
1940
1941static u32 get_seed2(int a, int b)
1942{
1943 const u32 seed2[5] = {
1944 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1945 0x5b6db6db,
1946 };
1947 u32 r;
1948 r = seed2[(a + (a >= 10)) / 5];
1949 return b ? ~r : r;
1950}
1951
1952static int make_shift(int comp2, int comp5, int x)
1953{
1954 const u8 seed3[32] = {
1955 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1956 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1957 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1958 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1959 };
1960
1961 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1962}
1963
1964static u32 get_etalon(int flip, u32 addr)
1965{
1966 u32 mask_byte = 0;
1967 int comp1 = (addr >> 1) & 1;
1968 int comp2 = (addr >> 3) & 0x1f;
1969 int comp3 = (addr >> 8) & 0xf;
1970 int comp4 = (addr >> 12) & 0xf;
1971 int comp5 = (addr >> 16) & 0x1f;
1972 u32 mask_bit = ~(0x10001 << comp3);
1973 u32 part1;
1974 u32 part2;
1975 int byte;
1976
1977 part2 =
1978 ((seed1[comp5] >>
1979 make_shift(comp2, comp5,
1980 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1981 part1 =
1982 ((seed1[comp5] >>
1983 make_shift(comp2, comp5,
1984 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1985
1986 for (byte = 0; byte < 4; byte++)
1987 if ((get_seed2(comp5, comp4) >>
1988 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1989 mask_byte |= 0xff << (8 * byte);
1990
1991 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1992 (comp3 + 16));
1993}
1994
1995static void
1996write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1997 char flip)
1998{
1999 int i;
2000 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002001 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2002 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002003}
2004
2005static u8
2006check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2007 char flip)
2008{
2009 u8 failmask = 0;
2010 u32 failxor[2];
2011 int i;
2012 int comp1, comp2, comp3;
2013
2014 failxor[0] = 0;
2015 failxor[1] = 0;
2016
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002017 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002018 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2019 for (comp1 = 0; comp1 < 16; comp1++)
2020 for (comp2 = 0; comp2 < 64; comp2++) {
2021 u32 addr =
2022 (totalrank << 28) | (region << 25) | (block
2023 << 16)
2024 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2025 2);
2026 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002027 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002028 }
2029 for (i = 0; i < 8; i++)
2030 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2031 failmask |= 1 << i;
2032 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002033 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002034 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2035 return failmask;
2036}
2037
2038static int check_bounded(unsigned short *vals, u16 bound)
2039{
2040 int i;
2041
2042 for (i = 0; i < 8; i++)
2043 if (vals[i] < bound)
2044 return 0;
2045 return 1;
2046}
2047
2048enum state {
2049 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2050};
2051
2052static int validate_state(enum state *in)
2053{
2054 int i;
2055 for (i = 0; i < 8; i++)
2056 if (in[i] != COMPLETE)
2057 return 0;
2058 return 1;
2059}
2060
2061static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002062do_fsm(enum state *state, u16 *counter,
2063 u8 fail_mask, int margin, int uplimit,
2064 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002065{
2066 int lane;
2067
2068 for (lane = 0; lane < 8; lane++) {
2069 int is_fail = (fail_mask >> lane) & 1;
2070 switch (state[lane]) {
2071 case BEFORE_USABLE:
2072 if (!is_fail) {
2073 counter[lane] = 1;
2074 state[lane] = AT_USABLE;
2075 break;
2076 }
2077 counter[lane] = 0;
2078 state[lane] = BEFORE_USABLE;
2079 break;
2080 case AT_USABLE:
2081 if (!is_fail) {
2082 ++counter[lane];
2083 if (counter[lane] >= margin) {
2084 state[lane] = AT_MARGIN;
2085 res_low[lane] = val - margin + 1;
2086 break;
2087 }
2088 state[lane] = 1;
2089 break;
2090 }
2091 counter[lane] = 0;
2092 state[lane] = BEFORE_USABLE;
2093 break;
2094 case AT_MARGIN:
2095 if (is_fail) {
2096 state[lane] = COMPLETE;
2097 res_high[lane] = val - 1;
2098 } else {
2099 counter[lane]++;
2100 state[lane] = AT_MARGIN;
2101 if (val == uplimit) {
2102 state[lane] = COMPLETE;
2103 res_high[lane] = uplimit;
2104 }
2105 }
2106 break;
2107 case COMPLETE:
2108 break;
2109 }
2110 }
2111}
2112
2113static void
2114train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2115 u8 total_rank, u8 reg_178, int first_run, int niter,
2116 timing_bounds_t * timings)
2117{
2118 int lane;
2119 enum state state[8];
2120 u16 count[8];
2121 u8 lower_usable[8];
2122 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002123 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002124 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002125 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002126
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002127 for (i = 0; i < 8; i++)
2128 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002129
2130 if (!first_run) {
2131 int is_all_ok = 1;
2132 for (lane = 0; lane < 8; lane++)
2133 if (timings[reg_178][channel][slot][rank][lane].
2134 smallest ==
2135 timings[reg_178][channel][slot][rank][lane].
2136 largest) {
2137 timings[reg_178][channel][slot][rank][lane].
2138 smallest = 0;
2139 timings[reg_178][channel][slot][rank][lane].
2140 largest = 0;
2141 is_all_ok = 0;
2142 }
2143 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002144 for (i = 0; i < 8; i++)
2145 state[i] = COMPLETE;
2146 }
2147 }
2148
2149 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2150 u8 failmask = 0;
2151 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2152 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2153 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002154 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002155 do_fsm(state, count, failmask, 5, 47, lower_usable,
2156 upper_usable, reg1b3);
2157 }
2158
2159 if (reg1b3) {
2160 write_1d0(0, 0x1b3, 6, 1);
2161 write_1d0(0, 0x1a3, 6, 1);
2162 for (lane = 0; lane < 8; lane++) {
2163 if (state[lane] == COMPLETE) {
2164 timings[reg_178][channel][slot][rank][lane].
2165 smallest =
2166 lower_usable[lane] +
2167 (info->training.
2168 lane_timings[0][channel][slot][rank][lane]
2169 & 0x3F) - 32;
2170 timings[reg_178][channel][slot][rank][lane].
2171 largest =
2172 upper_usable[lane] +
2173 (info->training.
2174 lane_timings[0][channel][slot][rank][lane]
2175 & 0x3F) - 32;
2176 }
2177 }
2178 }
2179
2180 if (!first_run) {
2181 for (lane = 0; lane < 8; lane++)
2182 if (state[lane] == COMPLETE) {
2183 write_500(info, channel,
2184 timings[reg_178][channel][slot][rank]
2185 [lane].smallest,
2186 get_timing_register_addr(lane, 0,
2187 slot, rank),
2188 9, 1);
2189 write_500(info, channel,
2190 timings[reg_178][channel][slot][rank]
2191 [lane].smallest +
2192 info->training.
2193 lane_timings[1][channel][slot][rank]
2194 [lane]
2195 -
2196 info->training.
2197 lane_timings[0][channel][slot][rank]
2198 [lane], get_timing_register_addr(lane,
2199 1,
2200 slot,
2201 rank),
2202 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002203 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002204 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002205 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002206
2207 do {
2208 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002209 for (i = 0; i < niter; i++) {
2210 if (failmask == 0xFF)
2211 break;
2212 failmask |=
2213 check_testing_type2(info, total_rank, 2, i,
2214 0);
2215 failmask |=
2216 check_testing_type2(info, total_rank, 3, i,
2217 1);
2218 }
Felix Held04be2dd2018-07-29 04:53:22 +02002219 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002220 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002221 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002222 if ((1 << lane) & failmask) {
2223 if (timings[reg_178][channel]
2224 [slot][rank][lane].
2225 largest <=
2226 timings[reg_178][channel]
2227 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002228 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002229 [lane] = -1;
2230 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002231 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002232 [lane] = 0;
2233 timings[reg_178]
2234 [channel][slot]
2235 [rank][lane].
2236 smallest++;
2237 write_500(info, channel,
2238 timings
2239 [reg_178]
2240 [channel]
2241 [slot][rank]
2242 [lane].
2243 smallest,
2244 get_timing_register_addr
2245 (lane, 0,
2246 slot, rank),
2247 9, 1);
2248 write_500(info, channel,
2249 timings
2250 [reg_178]
2251 [channel]
2252 [slot][rank]
2253 [lane].
2254 smallest +
2255 info->
2256 training.
2257 lane_timings
2258 [1][channel]
2259 [slot][rank]
2260 [lane]
2261 -
2262 info->
2263 training.
2264 lane_timings
2265 [0][channel]
2266 [slot][rank]
2267 [lane],
2268 get_timing_register_addr
2269 (lane, 1,
2270 slot, rank),
2271 9, 1);
2272 }
2273 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002274 num_successfully_checked[lane]
2275 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002276 }
2277 }
Felix Held04be2dd2018-07-29 04:53:22 +02002278 while (!check_bounded(num_successfully_checked, 2))
2279 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002280
2281 for (lane = 0; lane < 8; lane++)
2282 if (state[lane] == COMPLETE) {
2283 write_500(info, channel,
2284 timings[reg_178][channel][slot][rank]
2285 [lane].largest,
2286 get_timing_register_addr(lane, 0,
2287 slot, rank),
2288 9, 1);
2289 write_500(info, channel,
2290 timings[reg_178][channel][slot][rank]
2291 [lane].largest +
2292 info->training.
2293 lane_timings[1][channel][slot][rank]
2294 [lane]
2295 -
2296 info->training.
2297 lane_timings[0][channel][slot][rank]
2298 [lane], get_timing_register_addr(lane,
2299 1,
2300 slot,
2301 rank),
2302 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002303 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002304 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306
2307 do {
2308 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002309 for (i = 0; i < niter; i++) {
2310 if (failmask == 0xFF)
2311 break;
2312 failmask |=
2313 check_testing_type2(info, total_rank, 2, i,
2314 0);
2315 failmask |=
2316 check_testing_type2(info, total_rank, 3, i,
2317 1);
2318 }
2319
Felix Held04be2dd2018-07-29 04:53:22 +02002320 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002321 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002322 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002323 if ((1 << lane) & failmask) {
2324 if (timings[reg_178][channel]
2325 [slot][rank][lane].
2326 largest <=
2327 timings[reg_178][channel]
2328 [slot][rank][lane].
2329 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002330 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002331 [lane] = -1;
2332 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002333 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334 [lane] = 0;
2335 timings[reg_178]
2336 [channel][slot]
2337 [rank][lane].
2338 largest--;
2339 write_500(info, channel,
2340 timings
2341 [reg_178]
2342 [channel]
2343 [slot][rank]
2344 [lane].
2345 largest,
2346 get_timing_register_addr
2347 (lane, 0,
2348 slot, rank),
2349 9, 1);
2350 write_500(info, channel,
2351 timings
2352 [reg_178]
2353 [channel]
2354 [slot][rank]
2355 [lane].
2356 largest +
2357 info->
2358 training.
2359 lane_timings
2360 [1][channel]
2361 [slot][rank]
2362 [lane]
2363 -
2364 info->
2365 training.
2366 lane_timings
2367 [0][channel]
2368 [slot][rank]
2369 [lane],
2370 get_timing_register_addr
2371 (lane, 1,
2372 slot, rank),
2373 9, 1);
2374 }
2375 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002376 num_successfully_checked[lane]
2377 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002378 }
2379 }
2380 }
Felix Held04be2dd2018-07-29 04:53:22 +02002381 while (!check_bounded(num_successfully_checked, 3))
2382 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002383
2384 for (lane = 0; lane < 8; lane++) {
2385 write_500(info, channel,
2386 info->training.
2387 lane_timings[0][channel][slot][rank][lane],
2388 get_timing_register_addr(lane, 0, slot, rank),
2389 9, 1);
2390 write_500(info, channel,
2391 info->training.
2392 lane_timings[1][channel][slot][rank][lane],
2393 get_timing_register_addr(lane, 1, slot, rank),
2394 9, 1);
2395 if (timings[reg_178][channel][slot][rank][lane].
2396 largest <=
2397 timings[reg_178][channel][slot][rank][lane].
2398 smallest) {
2399 timings[reg_178][channel][slot][rank][lane].
2400 largest = 0;
2401 timings[reg_178][channel][slot][rank][lane].
2402 smallest = 0;
2403 }
2404 }
2405 }
2406}
2407
2408static void set_10b(struct raminfo *info, u8 val)
2409{
2410 int channel;
2411 int slot, rank;
2412 int lane;
2413
2414 if (read_1d0(0x10b, 6) == val)
2415 return;
2416
2417 write_1d0(val, 0x10b, 6, 1);
2418
2419 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2420 u16 reg_500;
2421 reg_500 = read_500(info, channel,
2422 get_timing_register_addr(lane, 0, slot,
2423 rank), 9);
2424 if (val == 1) {
2425 if (lut16[info->clock_speed_index] <= reg_500)
2426 reg_500 -= lut16[info->clock_speed_index];
2427 else
2428 reg_500 = 0;
2429 } else {
2430 reg_500 += lut16[info->clock_speed_index];
2431 }
2432 write_500(info, channel, reg_500,
2433 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2434 }
2435}
2436
2437static void set_ecc(int onoff)
2438{
2439 int channel;
2440 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2441 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002442 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002443 if (onoff)
2444 t |= 1;
2445 else
2446 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002447 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002448 }
2449}
2450
2451static void set_178(u8 val)
2452{
2453 if (val >= 31)
2454 val = val - 31;
2455 else
2456 val = 63 - val;
2457
2458 write_1d0(2 * val, 0x178, 7, 1);
2459}
2460
2461static void
2462write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2463 int type)
2464{
2465 int lane;
2466
2467 for (lane = 0; lane < 8; lane++)
2468 write_500(info, channel,
2469 info->training.
2470 lane_timings[type][channel][slot][rank][lane],
2471 get_timing_register_addr(lane, type, slot, rank), 9,
2472 0);
2473}
2474
2475static void
2476try_timing_offsets(struct raminfo *info, int channel,
2477 int slot, int rank, int totalrank)
2478{
2479 u16 count[8];
2480 enum state state[8];
2481 u8 lower_usable[8], upper_usable[8];
2482 int lane;
2483 int i;
2484 int flip = 1;
2485 int timing_offset;
2486
2487 for (i = 0; i < 8; i++)
2488 state[i] = BEFORE_USABLE;
2489
2490 memset(count, 0, sizeof(count));
2491
2492 for (lane = 0; lane < 8; lane++)
2493 write_500(info, channel,
2494 info->training.
2495 lane_timings[2][channel][slot][rank][lane] + 32,
2496 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2497
2498 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2499 timing_offset++) {
2500 u8 failmask;
2501 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2502 failmask = 0;
2503 for (i = 0; i < 2 && failmask != 0xff; i++) {
2504 flip = !flip;
2505 write_testing(info, totalrank, flip);
2506 failmask |= check_testing(info, totalrank, flip);
2507 }
2508 do_fsm(state, count, failmask, 10, 63, lower_usable,
2509 upper_usable, timing_offset);
2510 }
2511 write_1d0(0, 0x1bb, 6, 1);
2512 dump_timings(info);
2513 if (!validate_state(state))
2514 die("Couldn't discover DRAM timings (1)\n");
2515
2516 for (lane = 0; lane < 8; lane++) {
2517 u8 bias = 0;
2518
2519 if (info->silicon_revision) {
2520 int usable_length;
2521
2522 usable_length = upper_usable[lane] - lower_usable[lane];
2523 if (usable_length >= 20) {
2524 bias = usable_length / 2 - 10;
2525 if (bias >= 2)
2526 bias = 2;
2527 }
2528 }
2529 write_500(info, channel,
2530 info->training.
2531 lane_timings[2][channel][slot][rank][lane] +
2532 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2533 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2534 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2535 info->training.lane_timings[2][channel][slot][rank][lane] +
2536 lower_usable[lane];
2537 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2538 info->training.lane_timings[2][channel][slot][rank][lane] +
2539 upper_usable[lane];
2540 info->training.timing2_offset[channel][slot][rank][lane] =
2541 info->training.lane_timings[2][channel][slot][rank][lane];
2542 }
2543}
2544
2545static u8
2546choose_training(struct raminfo *info, int channel, int slot, int rank,
2547 int lane, timing_bounds_t * timings, u8 center_178)
2548{
2549 u16 central_weight;
2550 u16 side_weight;
2551 unsigned int sum = 0, count = 0;
2552 u8 span;
2553 u8 lower_margin, upper_margin;
2554 u8 reg_178;
2555 u8 result;
2556
2557 span = 12;
2558 central_weight = 20;
2559 side_weight = 20;
2560 if (info->silicon_revision == 1 && channel == 1) {
2561 central_weight = 5;
2562 side_weight = 20;
2563 if ((info->
2564 populated_ranks_mask[1] ^ (info->
2565 populated_ranks_mask[1] >> 2)) &
2566 1)
2567 span = 18;
2568 }
2569 if ((info->populated_ranks_mask[0] & 5) == 5) {
2570 central_weight = 20;
2571 side_weight = 20;
2572 }
2573 if (info->clock_speed_index >= 2
2574 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2575 if (info->silicon_revision == 1) {
2576 switch (channel) {
2577 case 0:
2578 if (lane == 1) {
2579 central_weight = 10;
2580 side_weight = 20;
2581 }
2582 break;
2583 case 1:
2584 if (lane == 6) {
2585 side_weight = 5;
2586 central_weight = 20;
2587 }
2588 break;
2589 }
2590 }
2591 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2592 side_weight = 5;
2593 central_weight = 20;
2594 }
2595 }
2596 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2597 reg_178 += span) {
2598 u8 smallest;
2599 u8 largest;
2600 largest = timings[reg_178][channel][slot][rank][lane].largest;
2601 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2602 if (largest - smallest + 1 >= 5) {
2603 unsigned int weight;
2604 if (reg_178 == center_178)
2605 weight = central_weight;
2606 else
2607 weight = side_weight;
2608 sum += weight * (largest + smallest);
2609 count += weight;
2610 }
2611 }
2612 dump_timings(info);
2613 if (count == 0)
2614 die("Couldn't discover DRAM timings (2)\n");
2615 result = sum / (2 * count);
2616 lower_margin =
2617 result - timings[center_178][channel][slot][rank][lane].smallest;
2618 upper_margin =
2619 timings[center_178][channel][slot][rank][lane].largest - result;
2620 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002621 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002622 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002623 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002624 return result;
2625}
2626
2627#define STANDARD_MIN_MARGIN 5
2628
2629static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2630{
2631 u16 margin[64];
2632 int lane, rank, slot, channel;
2633 u8 reg178;
2634 int count = 0, sum = 0;
2635
2636 for (reg178 = reg178_min[info->clock_speed_index];
2637 reg178 < reg178_max[info->clock_speed_index];
2638 reg178 += reg178_step[info->clock_speed_index]) {
2639 margin[reg178] = -1;
2640 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2641 int curmargin =
2642 timings[reg178][channel][slot][rank][lane].largest -
2643 timings[reg178][channel][slot][rank][lane].
2644 smallest + 1;
2645 if (curmargin < margin[reg178])
2646 margin[reg178] = curmargin;
2647 }
2648 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2649 u16 weight;
2650 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2651 sum += weight * reg178;
2652 count += weight;
2653 }
2654 }
2655 dump_timings(info);
2656 if (count == 0)
2657 die("Couldn't discover DRAM timings (3)\n");
2658
2659 u8 threshold;
2660
2661 for (threshold = 30; threshold >= 5; threshold--) {
2662 int usable_length = 0;
2663 int smallest_fount = 0;
2664 for (reg178 = reg178_min[info->clock_speed_index];
2665 reg178 < reg178_max[info->clock_speed_index];
2666 reg178 += reg178_step[info->clock_speed_index])
2667 if (margin[reg178] >= threshold) {
2668 usable_length +=
2669 reg178_step[info->clock_speed_index];
2670 info->training.reg178_largest =
2671 reg178 -
2672 2 * reg178_step[info->clock_speed_index];
2673
2674 if (!smallest_fount) {
2675 smallest_fount = 1;
2676 info->training.reg178_smallest =
2677 reg178 +
2678 reg178_step[info->
2679 clock_speed_index];
2680 }
2681 }
2682 if (usable_length >= 0x21)
2683 break;
2684 }
2685
2686 return sum / count;
2687}
2688
2689static int check_cached_sanity(struct raminfo *info)
2690{
2691 int lane;
2692 int slot, rank;
2693 int channel;
2694
2695 if (!info->cached_training)
2696 return 0;
2697
2698 for (channel = 0; channel < NUM_CHANNELS; channel++)
2699 for (slot = 0; slot < NUM_SLOTS; slot++)
2700 for (rank = 0; rank < NUM_RANKS; rank++)
2701 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2702 u16 cached_value, estimation_value;
2703 cached_value =
2704 info->cached_training->
2705 lane_timings[1][channel][slot][rank]
2706 [lane];
2707 if (cached_value >= 0x18
2708 && cached_value <= 0x1E7) {
2709 estimation_value =
2710 info->training.
2711 lane_timings[1][channel]
2712 [slot][rank][lane];
2713 if (estimation_value <
2714 cached_value - 24)
2715 return 0;
2716 if (estimation_value >
2717 cached_value + 24)
2718 return 0;
2719 }
2720 }
2721 return 1;
2722}
2723
2724static int try_cached_training(struct raminfo *info)
2725{
2726 u8 saved_243[2];
2727 u8 tm;
2728
2729 int channel, slot, rank, lane;
2730 int flip = 1;
2731 int i, j;
2732
2733 if (!check_cached_sanity(info))
2734 return 0;
2735
2736 info->training.reg178_center = info->cached_training->reg178_center;
2737 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2738 info->training.reg178_largest = info->cached_training->reg178_largest;
2739 memcpy(&info->training.timing_bounds,
2740 &info->cached_training->timing_bounds,
2741 sizeof(info->training.timing_bounds));
2742 memcpy(&info->training.timing_offset,
2743 &info->cached_training->timing_offset,
2744 sizeof(info->training.timing_offset));
2745
2746 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002747 saved_243[0] = MCHBAR8(0x243);
2748 saved_243[1] = MCHBAR8(0x643);
2749 MCHBAR8(0x243) = saved_243[0] | 2;
2750 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002751 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002752 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002753 if (read_1d0(0x10b, 6) & 1)
2754 set_10b(info, 0);
2755 for (tm = 0; tm < 2; tm++) {
2756 int totalrank;
2757
2758 set_178(tm ? info->cached_training->reg178_largest : info->
2759 cached_training->reg178_smallest);
2760
2761 totalrank = 0;
2762 /* Check timing ranges. With i == 0 we check smallest one and with
2763 i == 1 the largest bound. With j == 0 we check that on the bound
2764 it still works whereas with j == 1 we check that just outside of
2765 bound we fail.
2766 */
2767 FOR_POPULATED_RANKS_BACKWARDS {
2768 for (i = 0; i < 2; i++) {
2769 for (lane = 0; lane < 8; lane++) {
2770 write_500(info, channel,
2771 info->cached_training->
2772 timing2_bounds[channel][slot]
2773 [rank][lane][i],
2774 get_timing_register_addr(lane,
2775 3,
2776 slot,
2777 rank),
2778 9, 1);
2779
2780 if (!i)
2781 write_500(info, channel,
2782 info->
2783 cached_training->
2784 timing2_offset
2785 [channel][slot][rank]
2786 [lane],
2787 get_timing_register_addr
2788 (lane, 2, slot, rank),
2789 9, 1);
2790 write_500(info, channel,
2791 i ? info->cached_training->
2792 timing_bounds[tm][channel]
2793 [slot][rank][lane].
2794 largest : info->
2795 cached_training->
2796 timing_bounds[tm][channel]
2797 [slot][rank][lane].smallest,
2798 get_timing_register_addr(lane,
2799 0,
2800 slot,
2801 rank),
2802 9, 1);
2803 write_500(info, channel,
2804 info->cached_training->
2805 timing_offset[channel][slot]
2806 [rank][lane] +
2807 (i ? info->cached_training->
2808 timing_bounds[tm][channel]
2809 [slot][rank][lane].
2810 largest : info->
2811 cached_training->
2812 timing_bounds[tm][channel]
2813 [slot][rank][lane].
2814 smallest) - 64,
2815 get_timing_register_addr(lane,
2816 1,
2817 slot,
2818 rank),
2819 9, 1);
2820 }
2821 for (j = 0; j < 2; j++) {
2822 u8 failmask;
2823 u8 expected_failmask;
2824 char reg1b3;
2825
2826 reg1b3 = (j == 1) + 4;
2827 reg1b3 =
2828 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2829 write_1d0(reg1b3, 0x1bb, 6, 1);
2830 write_1d0(reg1b3, 0x1b3, 6, 1);
2831 write_1d0(reg1b3, 0x1a3, 6, 1);
2832
2833 flip = !flip;
2834 write_testing(info, totalrank, flip);
2835 failmask =
2836 check_testing(info, totalrank,
2837 flip);
2838 expected_failmask =
2839 j == 0 ? 0x00 : 0xff;
2840 if (failmask != expected_failmask)
2841 goto fail;
2842 }
2843 }
2844 totalrank++;
2845 }
2846 }
2847
2848 set_178(info->cached_training->reg178_center);
2849 if (info->use_ecc)
2850 set_ecc(1);
2851 write_training_data(info);
2852 write_1d0(0, 322, 3, 1);
2853 info->training = *info->cached_training;
2854
2855 write_1d0(0, 0x1bb, 6, 1);
2856 write_1d0(0, 0x1b3, 6, 1);
2857 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002858 MCHBAR8(0x243) = saved_243[0];
2859 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002860
2861 return 1;
2862
2863fail:
2864 FOR_POPULATED_RANKS {
2865 write_500_timings_type(info, channel, slot, rank, 1);
2866 write_500_timings_type(info, channel, slot, rank, 2);
2867 write_500_timings_type(info, channel, slot, rank, 3);
2868 }
2869
2870 write_1d0(0, 0x1bb, 6, 1);
2871 write_1d0(0, 0x1b3, 6, 1);
2872 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002873 MCHBAR8(0x243) = saved_243[0];
2874 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002875
2876 return 0;
2877}
2878
2879static void do_ram_training(struct raminfo *info)
2880{
2881 u8 saved_243[2];
2882 int totalrank = 0;
2883 u8 reg_178;
2884 int niter;
2885
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002886 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002887 int lane, rank, slot, channel;
2888 u8 reg178_center;
2889
2890 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002891 saved_243[0] = MCHBAR8(0x243);
2892 saved_243[1] = MCHBAR8(0x643);
2893 MCHBAR8(0x243) = saved_243[0] | 2;
2894 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002895 switch (info->clock_speed_index) {
2896 case 0:
2897 niter = 5;
2898 break;
2899 case 1:
2900 niter = 10;
2901 break;
2902 default:
2903 niter = 19;
2904 break;
2905 }
2906 set_ecc(0);
2907
2908 FOR_POPULATED_RANKS_BACKWARDS {
2909 int i;
2910
2911 write_500_timings_type(info, channel, slot, rank, 0);
2912
2913 write_testing(info, totalrank, 0);
2914 for (i = 0; i < niter; i++) {
2915 write_testing_type2(info, totalrank, 2, i, 0);
2916 write_testing_type2(info, totalrank, 3, i, 1);
2917 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002918 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002919 totalrank++;
2920 }
2921
2922 if (reg178_min[info->clock_speed_index] <
2923 reg178_max[info->clock_speed_index])
2924 memset(timings[reg178_min[info->clock_speed_index]], 0,
2925 sizeof(timings[0]) *
2926 (reg178_max[info->clock_speed_index] -
2927 reg178_min[info->clock_speed_index]));
2928 for (reg_178 = reg178_min[info->clock_speed_index];
2929 reg_178 < reg178_max[info->clock_speed_index];
2930 reg_178 += reg178_step[info->clock_speed_index]) {
2931 totalrank = 0;
2932 set_178(reg_178);
2933 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2934 for (slot = 0; slot < NUM_SLOTS; slot++)
2935 for (rank = 0; rank < NUM_RANKS; rank++) {
2936 memset(&timings[reg_178][channel][slot]
2937 [rank][0].smallest, 0, 16);
2938 if (info->
2939 populated_ranks[channel][slot]
2940 [rank]) {
2941 train_ram_at_178(info, channel,
2942 slot, rank,
2943 totalrank,
2944 reg_178, 1,
2945 niter,
2946 timings);
2947 totalrank++;
2948 }
2949 }
2950 }
2951
2952 reg178_center = choose_reg178(info, timings);
2953
2954 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2955 info->training.timing_bounds[0][channel][slot][rank][lane].
2956 smallest =
2957 timings[info->training.
2958 reg178_smallest][channel][slot][rank][lane].
2959 smallest;
2960 info->training.timing_bounds[0][channel][slot][rank][lane].
2961 largest =
2962 timings[info->training.
2963 reg178_smallest][channel][slot][rank][lane].largest;
2964 info->training.timing_bounds[1][channel][slot][rank][lane].
2965 smallest =
2966 timings[info->training.
2967 reg178_largest][channel][slot][rank][lane].smallest;
2968 info->training.timing_bounds[1][channel][slot][rank][lane].
2969 largest =
2970 timings[info->training.
2971 reg178_largest][channel][slot][rank][lane].largest;
2972 info->training.timing_offset[channel][slot][rank][lane] =
2973 info->training.lane_timings[1][channel][slot][rank][lane]
2974 -
2975 info->training.lane_timings[0][channel][slot][rank][lane] +
2976 64;
2977 }
2978
2979 if (info->silicon_revision == 1
2980 && (info->
2981 populated_ranks_mask[1] ^ (info->
2982 populated_ranks_mask[1] >> 2)) & 1) {
2983 int ranks_after_channel1;
2984
2985 totalrank = 0;
2986 for (reg_178 = reg178_center - 18;
2987 reg_178 <= reg178_center + 18; reg_178 += 18) {
2988 totalrank = 0;
2989 set_178(reg_178);
2990 for (slot = 0; slot < NUM_SLOTS; slot++)
2991 for (rank = 0; rank < NUM_RANKS; rank++) {
2992 if (info->
2993 populated_ranks[1][slot][rank]) {
2994 train_ram_at_178(info, 1, slot,
2995 rank,
2996 totalrank,
2997 reg_178, 0,
2998 niter,
2999 timings);
3000 totalrank++;
3001 }
3002 }
3003 }
3004 ranks_after_channel1 = totalrank;
3005
3006 for (reg_178 = reg178_center - 12;
3007 reg_178 <= reg178_center + 12; reg_178 += 12) {
3008 totalrank = ranks_after_channel1;
3009 set_178(reg_178);
3010 for (slot = 0; slot < NUM_SLOTS; slot++)
3011 for (rank = 0; rank < NUM_RANKS; rank++)
3012 if (info->
3013 populated_ranks[0][slot][rank]) {
3014 train_ram_at_178(info, 0, slot,
3015 rank,
3016 totalrank,
3017 reg_178, 0,
3018 niter,
3019 timings);
3020 totalrank++;
3021 }
3022
3023 }
3024 } else {
3025 for (reg_178 = reg178_center - 12;
3026 reg_178 <= reg178_center + 12; reg_178 += 12) {
3027 totalrank = 0;
3028 set_178(reg_178);
3029 FOR_POPULATED_RANKS_BACKWARDS {
3030 train_ram_at_178(info, channel, slot, rank,
3031 totalrank, reg_178, 0, niter,
3032 timings);
3033 totalrank++;
3034 }
3035 }
3036 }
3037
3038 set_178(reg178_center);
3039 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3040 u16 tm0;
3041
3042 tm0 =
3043 choose_training(info, channel, slot, rank, lane, timings,
3044 reg178_center);
3045 write_500(info, channel, tm0,
3046 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3047 write_500(info, channel,
3048 tm0 +
3049 info->training.
3050 lane_timings[1][channel][slot][rank][lane] -
3051 info->training.
3052 lane_timings[0][channel][slot][rank][lane],
3053 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3054 }
3055
3056 totalrank = 0;
3057 FOR_POPULATED_RANKS_BACKWARDS {
3058 try_timing_offsets(info, channel, slot, rank, totalrank);
3059 totalrank++;
3060 }
Felix Held04be2dd2018-07-29 04:53:22 +02003061 MCHBAR8(0x243) = saved_243[0];
3062 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003063 write_1d0(0, 0x142, 3, 1);
3064 info->training.reg178_center = reg178_center;
3065}
3066
3067static void ram_training(struct raminfo *info)
3068{
3069 u16 saved_fc4;
3070
Felix Held04be2dd2018-07-29 04:53:22 +02003071 saved_fc4 = MCHBAR16(0xfc4);
3072 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003073
3074 if (info->revision >= 8)
3075 read_4090(info);
3076
3077 if (!try_cached_training(info))
3078 do_ram_training(info);
3079 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3080 && info->clock_speed_index < 2)
3081 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003082 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003083}
3084
Angel Pons7a87c922021-01-15 22:50:41 +01003085u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003086{
3087 int slot, rank, lane;
3088 u16 ret = 0;
3089
Felix Held04be2dd2018-07-29 04:53:22 +02003090 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003091 return 384;
3092
3093 if (info->revision < 8)
3094 return 256;
3095
3096 for (slot = 0; slot < NUM_SLOTS; slot++)
3097 for (rank = 0; rank < NUM_RANKS; rank++)
3098 if (info->populated_ranks[channel][slot][rank])
3099 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003100 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003101 get_timing_register_addr
3102 (lane, 0, slot,
3103 rank), 9));
3104 return ret;
3105}
3106
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003107static void dmi_setup(void)
3108{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003109 gav(DMIBAR8(0x254));
3110 DMIBAR8(0x254) = 0x1;
3111 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003112 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003113
Angel Ponsd071c4d2020-09-14 23:51:35 +02003114 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003115
3116 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3117 DEFAULT_GPIOBASE | 0x38);
3118 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3119}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003120
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003121void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003122{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003123 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003124 u16 ggc;
3125 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003126
Felix Held04be2dd2018-07-29 04:53:22 +02003127 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003128 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3129 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003130 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003131 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003132 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003133
3134 dmi_setup();
3135
Felix Held04be2dd2018-07-29 04:53:22 +02003136 MCHBAR16(0x1170) = 0xa880;
3137 MCHBAR8(0x11c1) = 0x1;
3138 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003139 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003140
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003141 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3142 /* 0 for 32MB */
3143 gfxsize = 0;
3144 }
3145
3146 ggc = 0xb00 | ((gfxsize + 5) << 4);
3147
Angel Pons16fe1e02020-07-22 16:12:33 +02003148 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003149
3150 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003151 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003152
3153 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003154 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003155 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003156 MCHBAR16_OR(0x2c30, 0x200);
3157 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003158 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003159 pci_read_config8(GMA, MSAC); // = 0x2
3160 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003161 RCBA8(0x2318);
3162 RCBA8(0x2318) = 0x47;
3163 RCBA8(0x2320);
3164 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003165 }
3166
Felix Heldf83d80b2018-07-29 05:30:30 +02003167 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003168
Angel Pons16fe1e02020-07-22 16:12:33 +02003169 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003170 gav(RCBA32(0x3428));
3171 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003172}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003173
Angel Pons26681912021-01-15 21:36:28 +01003174static u8 get_bits_420(const u32 reg32)
3175{
3176 u8 val = 0;
3177 val |= (reg32 >> 4) & (1 << 0);
3178 val |= (reg32 >> 2) & (1 << 1);
3179 val |= (reg32 >> 0) & (1 << 2);
3180 return val;
3181}
3182
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003183void raminit(const int s3resume, const u8 *spd_addrmap)
3184{
Martin Roth468d02c2019-10-23 21:44:42 -06003185 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003186 struct raminfo info;
3187 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003188 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003189
Felix Held04be2dd2018-07-29 04:53:22 +02003190 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003191
3192 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3193
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003194 memset(&info, 0x5a, sizeof(info));
3195
3196 info.last_500_command[0] = 0;
3197 info.last_500_command[1] = 0;
3198
3199 info.fsb_frequency = 135 * 2;
3200 info.board_lane_delay[0] = 0x14;
3201 info.board_lane_delay[1] = 0x07;
3202 info.board_lane_delay[2] = 0x07;
3203 info.board_lane_delay[3] = 0x08;
3204 info.board_lane_delay[4] = 0x56;
3205 info.board_lane_delay[5] = 0x04;
3206 info.board_lane_delay[6] = 0x04;
3207 info.board_lane_delay[7] = 0x05;
3208 info.board_lane_delay[8] = 0x10;
3209
3210 info.training.reg_178 = 0;
3211 info.training.reg_10b = 0;
3212
Angel Ponsa3868292021-01-15 22:10:13 +01003213 /* Wait for some bit, maybe TXT clear. */
3214 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3215 ;
3216
3217 /* Wait for ME to be ready */
3218 intel_early_me_init();
3219 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003220
3221 /* before SPD */
3222 timestamp_add_now(101);
3223
Felix Held29a9c072018-07-29 01:34:45 +02003224 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003225 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3226
3227 info.use_ecc = 1;
3228 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003229 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003230 int v;
3231 int try;
3232 int addr;
3233 const u8 useful_addresses[] = {
3234 DEVICE_TYPE,
3235 MODULE_TYPE,
3236 DENSITY,
3237 RANKS_AND_DQ,
3238 MEMORY_BUS_WIDTH,
3239 TIMEBASE_DIVIDEND,
3240 TIMEBASE_DIVISOR,
3241 CYCLETIME,
3242 CAS_LATENCIES_LSB,
3243 CAS_LATENCIES_MSB,
3244 CAS_LATENCY_TIME,
3245 0x11, 0x12, 0x13, 0x14, 0x15,
3246 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3247 0x1c, 0x1d,
3248 THERMAL_AND_REFRESH,
3249 0x20,
3250 REFERENCE_RAW_CARD_USED,
3251 RANK1_ADDRESS_MAPPING,
3252 0x75, 0x76, 0x77, 0x78,
3253 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3254 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3255 0x85, 0x86, 0x87, 0x88,
3256 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3257 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3258 0x95
3259 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003260 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003261 continue;
3262 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003263 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003264 DEVICE_TYPE);
3265 if (v >= 0)
3266 break;
3267 }
3268 if (v < 0)
3269 continue;
3270 for (addr = 0;
3271 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003272 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003273 gav(info.
3274 spd[channel][0][useful_addresses
3275 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003276 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003277 useful_addresses
3278 [addr]));
3279 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3280 die("Only DDR3 is supported");
3281
3282 v = info.spd[channel][0][RANKS_AND_DQ];
3283 info.populated_ranks[channel][0][0] = 1;
3284 info.populated_ranks[channel][0][1] =
3285 ((v >> 3) & 7);
3286 if (((v >> 3) & 7) > 1)
3287 die("At most 2 ranks are supported");
3288 if ((v & 7) == 0 || (v & 7) > 2)
3289 die("Only x8 and x16 modules are supported");
3290 if ((info.
3291 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3292 && (info.
3293 spd[channel][slot][MODULE_TYPE] & 0xF)
3294 != 3)
3295 die("Registered memory is not supported");
3296 info.is_x16_module[channel][0] = (v & 7) - 1;
3297 info.density[channel][slot] =
3298 info.spd[channel][slot][DENSITY] & 0xF;
3299 if (!
3300 (info.
3301 spd[channel][slot][MEMORY_BUS_WIDTH] &
3302 0x18))
3303 info.use_ecc = 0;
3304 }
3305
3306 gav(0x55);
3307
3308 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3309 int v = 0;
3310 for (slot = 0; slot < NUM_SLOTS; slot++)
3311 for (rank = 0; rank < NUM_RANKS; rank++)
3312 v |= info.
3313 populated_ranks[channel][slot][rank]
3314 << (2 * slot + rank);
3315 info.populated_ranks_mask[channel] = v;
3316 }
3317
3318 gav(0x55);
3319
Angel Pons16fe1e02020-07-22 16:12:33 +02003320 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003321 }
3322
3323 /* after SPD */
3324 timestamp_add_now(102);
3325
Felix Held04be2dd2018-07-29 04:53:22 +02003326 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003327
3328 collect_system_info(&info);
3329 calculate_timings(&info);
3330
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003331 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003332 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003333 if (x2ca8 == 0 && (reg8 & 0x80)) {
3334 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3335 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3336 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3337 */
3338
3339 /* Clear bit7. */
3340
3341 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3342 (reg8 & ~(1 << 7)));
3343
3344 printk(BIOS_INFO,
3345 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003346 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003347 }
3348 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003349
3350 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003351 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3352 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003353
3354 compute_derived_timings(&info);
3355
3356 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003357 gav(MCHBAR8(0x164));
3358 MCHBAR8(0x164) = 0x26;
3359 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003360 }
3361
Felix Held04be2dd2018-07-29 04:53:22 +02003362 MCHBAR32_OR(0x18b4, 0x210000);
3363 MCHBAR32_OR(0x1890, 0x2000000);
3364 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003365
Angel Ponsa457e352020-07-22 18:17:33 +02003366 gav(pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS)); // !!!!
3367 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003368
Felix Held04be2dd2018-07-29 04:53:22 +02003369 gav(MCHBAR16(0x2c10));
3370 MCHBAR16(0x2c10) = 0x412;
3371 gav(MCHBAR16(0x2c10));
3372 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003373
Felix Held04be2dd2018-07-29 04:53:22 +02003374 gav(MCHBAR8(0x2ca8)); // !!!!
3375 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003376
Angel Ponsa457e352020-07-22 18:17:33 +02003377 pci_read_config32(QPI_PHY_0, QPI_PHY_CONTROL); // !!!!
3378 pci_write_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003379 gav(MCHBAR32(0x1c04)); // !!!!
3380 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003381
3382 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003383 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003384 }
3385
Felix Held04be2dd2018-07-29 04:53:22 +02003386 MCHBAR32(0x18d8) = 0x120000;
3387 MCHBAR32(0x18dc) = 0x30a484a;
Angel Ponsa457e352020-07-22 18:17:33 +02003388 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
3389 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003390 MCHBAR32(0x18d8) = 0x40000;
3391 MCHBAR32(0x18dc) = 0xb000000;
Angel Ponsa457e352020-07-22 18:17:33 +02003392 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
3393 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003394 MCHBAR32(0x18d8) = 0x180000;
3395 MCHBAR32(0x18dc) = 0xc0000142;
Angel Ponsa457e352020-07-22 18:17:33 +02003396 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
3397 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003398 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003399
Felix Held04be2dd2018-07-29 04:53:22 +02003400 gav(MCHBAR32(0x18dc)); // !!!!
3401 MCHBAR32(0x18dc) = 0x3;
3402 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003403
3404 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003405 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406 }
3407
Felix Held04be2dd2018-07-29 04:53:22 +02003408 MCHBAR32(0x188c) = 0x20bc09;
Angel Ponsa457e352020-07-22 18:17:33 +02003409 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003410 MCHBAR32(0x1a10) = 0x4200010e;
3411 MCHBAR32_OR(0x18b8, 0x200);
3412 gav(MCHBAR32(0x1918)); // !!!!
3413 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003414
Felix Held04be2dd2018-07-29 04:53:22 +02003415 gav(MCHBAR32(0x18b8)); // !!!!
3416 MCHBAR32(0x18b8) = 0xe00;
3417 gav(MCHBAR32(0x182c)); // !!!!
3418 MCHBAR32(0x182c) = 0x10202;
Angel Ponsa457e352020-07-22 18:17:33 +02003419 gav(pci_read_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT)); // !!!!
3420 pci_write_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003421 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3422 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003423
Felix Held04be2dd2018-07-29 04:53:22 +02003424 MCHBAR32_AND(0x18b4, 0xffff7fff);
3425 gav(MCHBAR32(0x1a68)); // !!!!
3426 MCHBAR32(0x1a68) = 0x343800;
3427 gav(MCHBAR32(0x1e68)); // !!!!
3428 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003429
3430 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003431 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003432 }
3433
Angel Pons08143572020-07-22 17:47:06 +02003434 pci_read_config32(QPI_LINK_0, QPI_QPILCL); // !!!!
3435 pci_write_config32(QPI_LINK_0, QPI_QPILCL, 0x140000);
3436 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
3437 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, 0x64555);
3438 pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS); // !!!!
Angel Pons9addda32020-07-22 18:37:32 +02003439 pci_read_config32(QPI_NON_CORE, MIRROR_PORT_CTL); // !!!!
3440 pci_write_config32(QPI_NON_CORE, MIRROR_PORT_CTL, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003441 gav(MCHBAR32(0x1af0)); // !!!!
3442 gav(MCHBAR32(0x1af0)); // !!!!
3443 MCHBAR32(0x1af0) = 0x1f020003;
3444 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003445
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003446 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003447 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448 }
3449
Felix Held04be2dd2018-07-29 04:53:22 +02003450 gav(MCHBAR32(0x1890)); // !!!!
3451 MCHBAR32(0x1890) = 0x80102;
3452 gav(MCHBAR32(0x18b4)); // !!!!
3453 MCHBAR32(0x18b4) = 0x216000;
3454 MCHBAR32(0x18a4) = 0x22222222;
3455 MCHBAR32(0x18a8) = 0x22222222;
3456 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003457
3458 udelay(1000);
3459
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003460 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003461
Angel Pons7a87c922021-01-15 22:50:41 +01003462 if (x2ca8 == 0)
3463 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003464
Angel Ponsc627dc92020-09-22 17:06:44 +02003465 MCHBAR32_OR(0x2c80, (1 << 24));
3466 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003467
Angel Ponsc627dc92020-09-22 17:06:44 +02003468 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003469
3470 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003471 MCHBAR8_AND(0x2ca8, ~3);
3472 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003473 /* This issues a CPU reset without resetting the platform */
3474 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003475 /* Write back the S3 state to PM1_CNT to let the reset CPU
3476 know it also needs to take the s3 path. */
3477 if (s3resume)
3478 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3479 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02003480 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01003481 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003482 }
Angel Pons7a87c922021-01-15 22:50:41 +01003483
Angel Ponsc627dc92020-09-22 17:06:44 +02003484 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003485
Angel Ponsc627dc92020-09-22 17:06:44 +02003486 MCHBAR32_AND(0x2c80, ~(1 << 24));
3487
Angel Pons9addda32020-07-22 18:37:32 +02003488 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003489
3490 {
3491 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
3492 u16 x2c10 = MCHBAR16(0x2c10);
3493 u16 value = MCHBAR16(0x2c00);
3494 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3495 value |= (1 << 7);
3496 else
3497 value &= ~(1 << 0);
3498
3499 MCHBAR16(0x2c00) = value;
3500 }
3501
3502 udelay(1000); // !!!!
3503
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 write_1d0(0, 0x33d, 0, 0);
3505 write_500(&info, 0, 0, 0xb61, 0, 0);
3506 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003507 MCHBAR32(0x1a30) = 0x0;
3508 MCHBAR32(0x1a34) = 0x0;
3509 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3510 (info.populated_ranks[0][0][0] * 0xa0);
3511 MCHBAR16(0x616) = 0x26a;
3512 MCHBAR32(0x134) = 0x856000;
3513 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02003514 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
3515 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003517 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
3518 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003519 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003520 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02003521 MCHBAR16(0x360 + (channel << 10)) = 0x909;
3522 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02003523 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
3524 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
3525 MCHBAR32(0x324 + (channel << 10)) = 0x0;
3526 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
3527 MCHBAR16(0x352 + (channel << 10)) = 0x505;
3528 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
3529 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
3530 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
3531 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
3532 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003533 }
3534
3535 write_1d0(0x4, 0x151, 4, 1);
3536 write_1d0(0, 0x142, 3, 1);
3537 rdmsr(0x1ac); // !!!!
3538 write_500(&info, 1, 1, 0x6b3, 4, 1);
3539 write_500(&info, 1, 1, 0x6cf, 4, 1);
3540
Angel Pons244f4552021-01-15 20:41:36 +01003541 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003542
3543 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3544 populated_ranks[0]
3545 [0][0]) << 0),
3546 0x1d1, 3, 1);
3547 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003548 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
3549 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003550 }
3551
3552 set_334(0);
3553
3554 program_base_timings(&info);
3555
Felix Held04be2dd2018-07-29 04:53:22 +02003556 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003557
3558 write_1d0(0x2, 0x1d5, 2, 1);
3559 write_1d0(0x20, 0x166, 7, 1);
3560 write_1d0(0x0, 0xeb, 3, 1);
3561 write_1d0(0x0, 0xf3, 6, 1);
3562
3563 for (channel = 0; channel < NUM_CHANNELS; channel++)
3564 for (lane = 0; lane < 9; lane++) {
3565 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3566 u8 a;
3567 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
3568 write_500(&info, channel, a, addr, 6, 1);
3569 }
3570
3571 udelay(1000);
3572
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003573 if (s3resume) {
3574 if (info.cached_training == NULL) {
3575 u32 reg32;
3576 printk(BIOS_ERR,
3577 "Couldn't find training data. Rebooting\n");
3578 reg32 = inl(DEFAULT_PMBASE + 0x04);
3579 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003580 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003581 }
3582 int tm;
3583 info.training = *info.cached_training;
3584 for (tm = 0; tm < 4; tm++)
3585 for (channel = 0; channel < NUM_CHANNELS; channel++)
3586 for (slot = 0; slot < NUM_SLOTS; slot++)
3587 for (rank = 0; rank < NUM_RANKS; rank++)
3588 for (lane = 0; lane < 9; lane++)
3589 write_500(&info,
3590 channel,
3591 info.training.
3592 lane_timings
3593 [tm][channel]
3594 [slot][rank]
3595 [lane],
3596 get_timing_register_addr
3597 (lane, tm,
3598 slot, rank),
3599 9, 0);
3600 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3601 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3602 }
3603
Felix Heldf83d80b2018-07-29 05:30:30 +02003604 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02003605 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02003606 MCHBAR8_OR(0x1f0, 0x1);
3607 while (MCHBAR8(0x1f0) & 1)
3608 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609
3610 program_board_delay(&info);
3611
Felix Held04be2dd2018-07-29 04:53:22 +02003612 MCHBAR8(0x5ff) = 0x0;
3613 MCHBAR8(0x5ff) = 0x80;
3614 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615
Felix Held04be2dd2018-07-29 04:53:22 +02003616 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02003617 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003618 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003619
3620 rmw_1d0(0x14b, 0x47, 0x30, 7);
3621 rmw_1d0(0xd6, 0x38, 7, 6);
3622 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623
3624 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003625 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626
Angel Ponsc627dc92020-09-22 17:06:44 +02003627 rmw_1d0(0x116, 0xe, 0, 4);
3628 rmw_1d0(0xae, 0x3e, 0, 6);
3629 rmw_1d0(0x300, 0x3e, 0, 6);
3630 MCHBAR16_AND(0x356, 0x7fff);
3631 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02003632 MCHBAR32_AND(0x140, ~0x07000000);
3633 MCHBAR32_AND(0x138, ~0x07000000);
3634 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003635 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02003636 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003637 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638
Angel Pons26681912021-01-15 21:36:28 +01003639 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 {
Angel Pons26681912021-01-15 21:36:28 +01003641 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3642 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3643 value_a1 = val_xa1;
3644 rmw_1d0(0x320, 0x38, val_2f3, 6);
3645 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3646 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647 }
3648
3649 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003650 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003651
Angel Pons244f4552021-01-15 20:41:36 +01003652 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003653 {
3654 if ((MCHBAR32(0x144) & 0x1f) < 0x13)
3655 value_a1 += 2;
3656 else
3657 value_a1 += 1;
3658
3659 if (value_a1 > 7)
3660 value_a1 = 7;
3661
3662 write_1d0(2, 0xae, 6, 1);
3663 write_1d0(2, 0x300, 6, 1);
3664 write_1d0(value_a1, 0x121, 3, 1);
3665 rmw_1d0(0xd6, 0x38, 4, 6);
3666 rmw_1d0(0x328, 0x38, 4, 6);
3667 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668
3669 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003670 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671
Felix Held04be2dd2018-07-29 04:53:22 +02003672 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
3673 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02003674 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003675 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003676
3677 {
Angel Pons26681912021-01-15 21:36:28 +01003678 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003679 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3680 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003681 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003682 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683
3684 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003685 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686
3687 set_334(1);
3688
Felix Held04be2dd2018-07-29 04:53:22 +02003689 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690
3691 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3692 write_500(&info, channel,
3693 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3694 1);
3695 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3696 }
Felix Held04be2dd2018-07-29 04:53:22 +02003697 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
3698 MCHBAR16(0x6c0) = 0x14a0;
3699 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
3700 MCHBAR16(0x232) = 0x8;
3701 /* 0x40004 or 0 depending on ? */
3702 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
3703 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
3704 MCHBAR32(0x128) = 0x2150d05;
3705 MCHBAR8(0x12c) = 0x1f;
3706 MCHBAR8(0x12d) = 0x56;
3707 MCHBAR8(0x12e) = 0x31;
3708 MCHBAR8(0x12f) = 0x0;
3709 MCHBAR8(0x271) = 0x2;
3710 MCHBAR8(0x671) = 0x2;
3711 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003713 MCHBAR32(0x294 + (channel << 10)) =
3714 (info.populated_ranks_mask[channel] & 3) << 16;
3715 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
3716 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003717 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02003718 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
3719 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003720
3721 if (!s3resume)
3722 jedec_init(&info);
3723
3724 int totalrank = 0;
3725 for (channel = 0; channel < NUM_CHANNELS; channel++)
3726 for (slot = 0; slot < NUM_SLOTS; slot++)
3727 for (rank = 0; rank < NUM_RANKS; rank++)
3728 if (info.populated_ranks[channel][slot][rank]) {
3729 jedec_read(&info, channel, slot, rank,
3730 totalrank, 0xa, 0x400);
3731 totalrank++;
3732 }
3733
Felix Held04be2dd2018-07-29 04:53:22 +02003734 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003735
Angel Ponsc627dc92020-09-22 17:06:44 +02003736 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
3737 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003738
3739 if (!s3resume) {
3740 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003741 MCHBAR32(0x294 + (channel << 10)) =
3742 (info.populated_ranks_mask[channel] & 3) << 16;
3743 MCHBAR16(0x298 + (channel << 10)) =
3744 info.populated_ranks[channel][0][0] |
3745 (info.populated_ranks[channel][0][1] << 5);
3746 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003748 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003749
3750 {
3751 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02003752 a = MCHBAR8(0x243);
3753 b = MCHBAR8(0x643);
3754 MCHBAR8(0x243) = a | 2;
3755 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003756 }
3757
3758 write_1d0(7, 0x19b, 3, 1);
3759 write_1d0(7, 0x1c0, 3, 1);
3760 write_1d0(4, 0x1c6, 4, 1);
3761 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003762 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02003763 MCHBAR32(0x584) = 0xfffff;
3764 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765
3766 for (channel = 0; channel < NUM_CHANNELS; channel++)
3767 for (slot = 0; slot < NUM_SLOTS; slot++)
3768 for (rank = 0; rank < NUM_RANKS; rank++)
3769 if (info.
3770 populated_ranks[channel][slot]
3771 [rank])
3772 config_rank(&info, s3resume,
3773 channel, slot,
3774 rank);
3775
Felix Held04be2dd2018-07-29 04:53:22 +02003776 MCHBAR8(0x243) = 0x1;
3777 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003778 }
3779
3780 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003781 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003782 write_26c(0, 0x820);
3783 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02003784 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003785 /* end */
3786
3787 if (s3resume) {
3788 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003789 MCHBAR32(0x294 + (channel << 10)) =
3790 (info.populated_ranks_mask[channel] & 3) << 16;
3791 MCHBAR16(0x298 + (channel << 10)) =
3792 info.populated_ranks[channel][0][0] |
3793 (info.populated_ranks[channel][0][1] << 5);
3794 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003795 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003796 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003797 }
3798
Felix Held04be2dd2018-07-29 04:53:22 +02003799 MCHBAR32_AND(0xfa4, ~0x01000002);
3800 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003801
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003802 /* Before training. */
3803 timestamp_add_now(103);
3804
3805 if (!s3resume)
3806 ram_training(&info);
3807
3808 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003809 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003810
3811 dump_timings(&info);
3812
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003813 program_modules_memory_map(&info, 0);
3814 program_total_memory_map(&info);
3815
3816 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02003817 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003818 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02003819 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02003821 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003822 else
Felix Held04be2dd2018-07-29 04:53:22 +02003823 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003824
Felix Held04be2dd2018-07-29 04:53:22 +02003825 MCHBAR32_AND(0xfac, ~0x80000000);
3826 MCHBAR32(0xfb4) = 0x4800;
3827 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
3828 MCHBAR32(0xe94) = 0x7ffff;
3829 MCHBAR32(0xfc0) = 0x80002040;
3830 MCHBAR32(0xfc4) = 0x701246;
3831 MCHBAR8_AND(0xfc8, ~0x70);
3832 MCHBAR32_OR(0xe5c, 0x1000000);
3833 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
3834 MCHBAR32(0x50) = 0x700b0;
3835 MCHBAR32(0x3c) = 0x10;
3836 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
3837 MCHBAR8_OR(0xff4, 0x2);
3838 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003839
Felix Held04be2dd2018-07-29 04:53:22 +02003840 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
3841 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
3842 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003843
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003844 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3845 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3846 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003847
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003848 {
3849 u32 eax;
3850
3851 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02003852 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
3853 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
3854 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855 }
3856
3857 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003858 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003860 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861 else
Felix Held04be2dd2018-07-29 04:53:22 +02003862 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863
Felix Held04be2dd2018-07-29 04:53:22 +02003864 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003865
Felix Held04be2dd2018-07-29 04:53:22 +02003866 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02003868 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869 else
Felix Held04be2dd2018-07-29 04:53:22 +02003870 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871 }
3872
Felix Held04be2dd2018-07-29 04:53:22 +02003873 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874
3875 {
3876 u8 al;
3877 al = 0xd;
3878 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3879 al += 2;
3880 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02003881 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003882 }
3883
3884 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003885 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
3886 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
3887 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
3888 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889 }
3890 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003891 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003892 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003893 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003894 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003895 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003896 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02003897 MCHBAR8_OR(0x1210, 2);
3898 MCHBAR32(0x1200) = 0x8800440;
3899 MCHBAR32(0x1204) = 0x53ff0453;
3900 MCHBAR32(0x1208) = 0x19002043;
3901 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003902
3903 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02003904 MCHBAR16(0x1214) = 0x220;
3905 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906 }
3907
Felix Held04be2dd2018-07-29 04:53:22 +02003908 MCHBAR8_OR(0x1214, 0x4);
3909 MCHBAR8(0x120c) = 0x1;
3910 MCHBAR8(0x1218) = 0x3;
3911 MCHBAR8(0x121a) = 0x3;
3912 MCHBAR8(0x121c) = 0x3;
3913 MCHBAR16(0xc14) = 0x0;
3914 MCHBAR16(0xc20) = 0x0;
3915 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
3917 /* revision dependent here. */
3918
Felix Held04be2dd2018-07-29 04:53:22 +02003919 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
3921 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02003922 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003923
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR16_OR(0x1230, 0x8000);
3925 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003926
3927 u8 bl, ebpb;
3928 u16 reg_1020;
3929
Felix Held04be2dd2018-07-29 04:53:22 +02003930 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
3931 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003932
Felix Held04be2dd2018-07-29 04:53:22 +02003933 MCHBAR32(0x1000) = 0x100;
3934 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935
3936 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003938 bl = reg_1020 >> 8;
3939 ebpb = reg_1020 & 0xff;
3940 } else {
3941 ebpb = 0;
3942 bl = 8;
3943 }
3944
3945 rdmsr(0x1a2);
3946
Felix Held04be2dd2018-07-29 04:53:22 +02003947 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952
Felix Held04be2dd2018-07-29 04:53:22 +02003953 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003955 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
3956 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003957 }
3958
3959 setup_heci_uma(&info);
3960
3961 if (info.uma_enabled) {
3962 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02003963 MCHBAR32_OR(0x11b0, 0x4000);
3964 MCHBAR32_OR(0x11b4, 0x4000);
3965 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003966
Felix Held04be2dd2018-07-29 04:53:22 +02003967 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
3968 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
3969 MCHBAR16_OR(0x1170, 0x1000);
3970
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003971 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003972
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003973 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02003974 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003975 ;
3976 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003977 }
3978
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003979 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3980 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003981 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02003982 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003983
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984 udelay(1000);
3985 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003986 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3987
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003988 if (!s3resume)
3989 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003990 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003991 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003992 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003993
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003994 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003995 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003996 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003997}