blob: f073ddae89325480baef1d28bf6e4d6e32ff527f [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
Angel Ponsb1821892020-09-14 19:29:53 +02001652union uma_reply {
1653 struct {
1654 u8 group_id;
1655 u8 command;
1656 u8 reserved;
1657 u8 result;
1658 u8 field2;
1659 u8 unk3[0x48 - 4 - 1];
1660 };
1661 u32 dwords[0x48 / sizeof(u32)];
1662} __packed;
1663
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664/* FIXME: Add timeout. */
Angel Ponsb1821892020-09-14 19:29:53 +02001665static int recv_heci_message(union uma_reply *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001666{
1667 struct mei_header head;
1668 int current_position;
1669
1670 current_position = 0;
1671 while (1) {
1672 u32 current_size;
1673 current_size = *message_size - current_position;
1674 if (recv_heci_packet
Angel Ponsb1821892020-09-14 19:29:53 +02001675 (&head, &message->dwords[current_position / sizeof(u32)],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676 &current_size) == -1)
1677 break;
1678 if (!current_size)
1679 break;
1680 current_position += current_size;
1681 if (head.is_complete) {
1682 *message_size = current_position;
1683 return 0;
1684 }
1685
1686 if (current_position >= *message_size)
1687 break;
1688 }
1689 *message_size = 0;
1690 return -1;
1691}
1692
Angel Pons55f11e22020-09-14 19:06:53 +02001693static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001694{
Angel Ponsb1821892020-09-14 19:29:53 +02001695 union uma_reply reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001696
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001697 struct uma_message {
1698 u8 group_id;
1699 u8 cmd;
1700 u8 reserved;
1701 u8 result;
1702 u32 c2;
1703 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001704 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001706 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001707 .group_id = 0,
1708 .cmd = MKHI_SET_UMA,
1709 .reserved = 0,
1710 .result = 0,
1711 .c2 = 0x82,
1712 .heci_uma_addr = heci_uma_addr,
1713 .heci_uma_size = heci_uma_size,
1714 .c3 = 0,
1715 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 u32 reply_size;
1717
Angel Ponseb537932020-09-14 19:18:11 +02001718 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001719
1720 reply_size = sizeof(reply);
Angel Ponsb1821892020-09-14 19:29:53 +02001721 if (recv_heci_message(&reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001722 return;
1723
1724 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1725 die("HECI init failed\n");
1726}
1727
1728static void setup_heci_uma(struct raminfo *info)
1729{
Angel Pons44479962021-02-24 23:08:27 +01001730 if (!info->memory_reserved_for_heci_mb || !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 return;
1732
Angel Pons36592bf2020-09-14 18:52:44 +02001733 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001735 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001736 info->memory_reserved_for_heci_mb)) << 20;
1737
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001738 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001740 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001741 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001742 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001743 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001744 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001745 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001746 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001747 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001748
Angel Ponsee7fb342021-01-28 14:11:55 +01001749 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001750 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001751
Angel Ponsee7fb342021-01-28 14:11:55 +01001752 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001753 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754 }
1755
Felix Held04be2dd2018-07-29 04:53:22 +02001756 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757
Angel Pons55f11e22020-09-14 19:06:53 +02001758 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001760 pci_write_config32(HECIDEV, 0x10, 0x0);
1761 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001762}
1763
1764static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1765{
1766 int ranks_in_channel;
1767 ranks_in_channel = info->populated_ranks[channel][0][0]
1768 + info->populated_ranks[channel][0][1]
1769 + info->populated_ranks[channel][1][0]
1770 + info->populated_ranks[channel][1][1];
1771
1772 /* empty channel */
1773 if (ranks_in_channel == 0)
1774 return 1;
1775
1776 if (ranks_in_channel != ranks)
1777 return 0;
1778 /* single slot */
1779 if (info->populated_ranks[channel][0][0] !=
1780 info->populated_ranks[channel][1][0])
1781 return 1;
1782 if (info->populated_ranks[channel][0][1] !=
1783 info->populated_ranks[channel][1][1])
1784 return 1;
1785 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1786 return 0;
1787 if (info->density[channel][0] != info->density[channel][1])
1788 return 0;
1789 return 1;
1790}
1791
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001792static void read_4090(struct raminfo *info)
1793{
1794 int i, channel, slot, rank, lane;
1795 for (i = 0; i < 2; i++)
1796 for (slot = 0; slot < NUM_SLOTS; slot++)
1797 for (rank = 0; rank < NUM_RANKS; rank++)
1798 for (lane = 0; lane < 9; lane++)
1799 info->training.
1800 lane_timings[0][i][slot][rank][lane]
1801 = 32;
1802
1803 for (i = 1; i < 4; i++)
1804 for (channel = 0; channel < NUM_CHANNELS; channel++)
1805 for (slot = 0; slot < NUM_SLOTS; slot++)
1806 for (rank = 0; rank < NUM_RANKS; rank++)
1807 for (lane = 0; lane < 9; lane++) {
1808 info->training.
1809 lane_timings[i][channel]
1810 [slot][rank][lane] =
1811 read_500(info, channel,
1812 get_timing_register_addr
1813 (lane, i, slot,
1814 rank), 9)
1815 + (i == 1) * 11; // !!!!
1816 }
1817
1818}
1819
1820static u32 get_etalon2(int flip, u32 addr)
1821{
1822 const u16 invmask[] = {
1823 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1824 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1825 };
1826 u32 ret;
1827 u32 comp4 = addr / 480;
1828 addr %= 480;
1829 u32 comp1 = addr & 0xf;
1830 u32 comp2 = (addr >> 4) & 1;
1831 u32 comp3 = addr >> 5;
1832
1833 if (comp4)
1834 ret = 0x1010101 << (comp4 - 1);
1835 else
1836 ret = 0;
1837 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1838 ret = ~ret;
1839
1840 return ret;
1841}
1842
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001843static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844{
1845 msr_t msr = {.lo = 0, .hi = 0 };
1846
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001847 wrmsr(MTRR_PHYS_BASE(3), msr);
1848 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849}
1850
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001851static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001852{
1853 msr_t msr;
1854 msr.lo = base | MTRR_TYPE_WRPROT;
1855 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001856 wrmsr(MTRR_PHYS_BASE(3), msr);
1857 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001858 & 0xffffffff);
1859 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001860 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001861}
1862
1863static void flush_cache(u32 start, u32 size)
1864{
1865 u32 end;
1866 u32 addr;
1867
1868 end = start + (ALIGN_DOWN(size + 4096, 4096));
1869 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001870 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871}
1872
1873static void clear_errors(void)
1874{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001875 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001876}
1877
1878static void write_testing(struct raminfo *info, int totalrank, int flip)
1879{
1880 int nwrites = 0;
1881 /* in 8-byte units. */
1882 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001883 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001884
Patrick Rudolph819c2062019-11-29 19:27:37 +01001885 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001886 for (offset = 0; offset < 9 * 480; offset += 2) {
1887 write32(base + offset * 8, get_etalon2(flip, offset));
1888 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1889 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1890 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1891 nwrites += 4;
1892 if (nwrites >= 320) {
1893 clear_errors();
1894 nwrites = 0;
1895 }
1896 }
1897}
1898
1899static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1900{
1901 u8 failmask = 0;
1902 int i;
1903 int comp1, comp2, comp3;
1904 u32 failxor[2] = { 0, 0 };
1905
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001906 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001907
1908 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1909 for (comp1 = 0; comp1 < 4; comp1++)
1910 for (comp2 = 0; comp2 < 60; comp2++) {
1911 u32 re[4];
1912 u32 curroffset =
1913 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1914 read128((total_rank << 28) | (curroffset << 3),
1915 (u64 *) re);
1916 failxor[0] |=
1917 get_etalon2(flip, curroffset) ^ re[0];
1918 failxor[1] |=
1919 get_etalon2(flip, curroffset) ^ re[1];
1920 failxor[0] |=
1921 get_etalon2(flip, curroffset | 1) ^ re[2];
1922 failxor[1] |=
1923 get_etalon2(flip, curroffset | 1) ^ re[3];
1924 }
1925 for (i = 0; i < 8; i++)
1926 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1927 failmask |= 1 << i;
1928 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001929 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001930 flush_cache((total_rank << 28), 1728 * 5 * 4);
1931 return failmask;
1932}
1933
1934const u32 seed1[0x18] = {
1935 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1936 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1937 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1938 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1939 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1940 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1941};
1942
1943static u32 get_seed2(int a, int b)
1944{
1945 const u32 seed2[5] = {
1946 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1947 0x5b6db6db,
1948 };
1949 u32 r;
1950 r = seed2[(a + (a >= 10)) / 5];
1951 return b ? ~r : r;
1952}
1953
1954static int make_shift(int comp2, int comp5, int x)
1955{
1956 const u8 seed3[32] = {
1957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1958 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1959 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1960 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1961 };
1962
1963 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1964}
1965
1966static u32 get_etalon(int flip, u32 addr)
1967{
1968 u32 mask_byte = 0;
1969 int comp1 = (addr >> 1) & 1;
1970 int comp2 = (addr >> 3) & 0x1f;
1971 int comp3 = (addr >> 8) & 0xf;
1972 int comp4 = (addr >> 12) & 0xf;
1973 int comp5 = (addr >> 16) & 0x1f;
1974 u32 mask_bit = ~(0x10001 << comp3);
1975 u32 part1;
1976 u32 part2;
1977 int byte;
1978
1979 part2 =
1980 ((seed1[comp5] >>
1981 make_shift(comp2, comp5,
1982 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1983 part1 =
1984 ((seed1[comp5] >>
1985 make_shift(comp2, comp5,
1986 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1987
1988 for (byte = 0; byte < 4; byte++)
1989 if ((get_seed2(comp5, comp4) >>
1990 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1991 mask_byte |= 0xff << (8 * byte);
1992
1993 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1994 (comp3 + 16));
1995}
1996
1997static void
1998write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1999 char flip)
2000{
2001 int i;
2002 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002003 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2004 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002005}
2006
2007static u8
2008check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2009 char flip)
2010{
2011 u8 failmask = 0;
2012 u32 failxor[2];
2013 int i;
2014 int comp1, comp2, comp3;
2015
2016 failxor[0] = 0;
2017 failxor[1] = 0;
2018
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002019 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002020 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2021 for (comp1 = 0; comp1 < 16; comp1++)
2022 for (comp2 = 0; comp2 < 64; comp2++) {
2023 u32 addr =
2024 (totalrank << 28) | (region << 25) | (block
2025 << 16)
2026 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2027 2);
2028 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002029 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002030 }
2031 for (i = 0; i < 8; i++)
2032 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2033 failmask |= 1 << i;
2034 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002035 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002036 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2037 return failmask;
2038}
2039
2040static int check_bounded(unsigned short *vals, u16 bound)
2041{
2042 int i;
2043
2044 for (i = 0; i < 8; i++)
2045 if (vals[i] < bound)
2046 return 0;
2047 return 1;
2048}
2049
2050enum state {
2051 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2052};
2053
2054static int validate_state(enum state *in)
2055{
2056 int i;
2057 for (i = 0; i < 8; i++)
2058 if (in[i] != COMPLETE)
2059 return 0;
2060 return 1;
2061}
2062
2063static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002064do_fsm(enum state *state, u16 *counter,
2065 u8 fail_mask, int margin, int uplimit,
2066 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002067{
2068 int lane;
2069
2070 for (lane = 0; lane < 8; lane++) {
2071 int is_fail = (fail_mask >> lane) & 1;
2072 switch (state[lane]) {
2073 case BEFORE_USABLE:
2074 if (!is_fail) {
2075 counter[lane] = 1;
2076 state[lane] = AT_USABLE;
2077 break;
2078 }
2079 counter[lane] = 0;
2080 state[lane] = BEFORE_USABLE;
2081 break;
2082 case AT_USABLE:
2083 if (!is_fail) {
2084 ++counter[lane];
2085 if (counter[lane] >= margin) {
2086 state[lane] = AT_MARGIN;
2087 res_low[lane] = val - margin + 1;
2088 break;
2089 }
2090 state[lane] = 1;
2091 break;
2092 }
2093 counter[lane] = 0;
2094 state[lane] = BEFORE_USABLE;
2095 break;
2096 case AT_MARGIN:
2097 if (is_fail) {
2098 state[lane] = COMPLETE;
2099 res_high[lane] = val - 1;
2100 } else {
2101 counter[lane]++;
2102 state[lane] = AT_MARGIN;
2103 if (val == uplimit) {
2104 state[lane] = COMPLETE;
2105 res_high[lane] = uplimit;
2106 }
2107 }
2108 break;
2109 case COMPLETE:
2110 break;
2111 }
2112 }
2113}
2114
2115static void
2116train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2117 u8 total_rank, u8 reg_178, int first_run, int niter,
2118 timing_bounds_t * timings)
2119{
2120 int lane;
2121 enum state state[8];
2122 u16 count[8];
2123 u8 lower_usable[8];
2124 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002125 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002126 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002127 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002128
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002129 for (i = 0; i < 8; i++)
2130 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002131
2132 if (!first_run) {
2133 int is_all_ok = 1;
2134 for (lane = 0; lane < 8; lane++)
2135 if (timings[reg_178][channel][slot][rank][lane].
2136 smallest ==
2137 timings[reg_178][channel][slot][rank][lane].
2138 largest) {
2139 timings[reg_178][channel][slot][rank][lane].
2140 smallest = 0;
2141 timings[reg_178][channel][slot][rank][lane].
2142 largest = 0;
2143 is_all_ok = 0;
2144 }
2145 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002146 for (i = 0; i < 8; i++)
2147 state[i] = COMPLETE;
2148 }
2149 }
2150
2151 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2152 u8 failmask = 0;
2153 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2154 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2155 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002156 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002157 do_fsm(state, count, failmask, 5, 47, lower_usable,
2158 upper_usable, reg1b3);
2159 }
2160
2161 if (reg1b3) {
2162 write_1d0(0, 0x1b3, 6, 1);
2163 write_1d0(0, 0x1a3, 6, 1);
2164 for (lane = 0; lane < 8; lane++) {
2165 if (state[lane] == COMPLETE) {
2166 timings[reg_178][channel][slot][rank][lane].
2167 smallest =
2168 lower_usable[lane] +
2169 (info->training.
2170 lane_timings[0][channel][slot][rank][lane]
2171 & 0x3F) - 32;
2172 timings[reg_178][channel][slot][rank][lane].
2173 largest =
2174 upper_usable[lane] +
2175 (info->training.
2176 lane_timings[0][channel][slot][rank][lane]
2177 & 0x3F) - 32;
2178 }
2179 }
2180 }
2181
2182 if (!first_run) {
2183 for (lane = 0; lane < 8; lane++)
2184 if (state[lane] == COMPLETE) {
2185 write_500(info, channel,
2186 timings[reg_178][channel][slot][rank]
2187 [lane].smallest,
2188 get_timing_register_addr(lane, 0,
2189 slot, rank),
2190 9, 1);
2191 write_500(info, channel,
2192 timings[reg_178][channel][slot][rank]
2193 [lane].smallest +
2194 info->training.
2195 lane_timings[1][channel][slot][rank]
2196 [lane]
2197 -
2198 info->training.
2199 lane_timings[0][channel][slot][rank]
2200 [lane], get_timing_register_addr(lane,
2201 1,
2202 slot,
2203 rank),
2204 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002205 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002206 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002207 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002208
2209 do {
2210 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002211 for (i = 0; i < niter; i++) {
2212 if (failmask == 0xFF)
2213 break;
2214 failmask |=
2215 check_testing_type2(info, total_rank, 2, i,
2216 0);
2217 failmask |=
2218 check_testing_type2(info, total_rank, 3, i,
2219 1);
2220 }
Felix Held04be2dd2018-07-29 04:53:22 +02002221 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002222 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002223 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002224 if ((1 << lane) & failmask) {
2225 if (timings[reg_178][channel]
2226 [slot][rank][lane].
2227 largest <=
2228 timings[reg_178][channel]
2229 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002230 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002231 [lane] = -1;
2232 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002233 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002234 [lane] = 0;
2235 timings[reg_178]
2236 [channel][slot]
2237 [rank][lane].
2238 smallest++;
2239 write_500(info, channel,
2240 timings
2241 [reg_178]
2242 [channel]
2243 [slot][rank]
2244 [lane].
2245 smallest,
2246 get_timing_register_addr
2247 (lane, 0,
2248 slot, rank),
2249 9, 1);
2250 write_500(info, channel,
2251 timings
2252 [reg_178]
2253 [channel]
2254 [slot][rank]
2255 [lane].
2256 smallest +
2257 info->
2258 training.
2259 lane_timings
2260 [1][channel]
2261 [slot][rank]
2262 [lane]
2263 -
2264 info->
2265 training.
2266 lane_timings
2267 [0][channel]
2268 [slot][rank]
2269 [lane],
2270 get_timing_register_addr
2271 (lane, 1,
2272 slot, rank),
2273 9, 1);
2274 }
2275 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002276 num_successfully_checked[lane]
2277 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002278 }
2279 }
Felix Held04be2dd2018-07-29 04:53:22 +02002280 while (!check_bounded(num_successfully_checked, 2))
2281 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002282
2283 for (lane = 0; lane < 8; lane++)
2284 if (state[lane] == COMPLETE) {
2285 write_500(info, channel,
2286 timings[reg_178][channel][slot][rank]
2287 [lane].largest,
2288 get_timing_register_addr(lane, 0,
2289 slot, rank),
2290 9, 1);
2291 write_500(info, channel,
2292 timings[reg_178][channel][slot][rank]
2293 [lane].largest +
2294 info->training.
2295 lane_timings[1][channel][slot][rank]
2296 [lane]
2297 -
2298 info->training.
2299 lane_timings[0][channel][slot][rank]
2300 [lane], get_timing_register_addr(lane,
2301 1,
2302 slot,
2303 rank),
2304 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002307 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308
2309 do {
2310 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002311 for (i = 0; i < niter; i++) {
2312 if (failmask == 0xFF)
2313 break;
2314 failmask |=
2315 check_testing_type2(info, total_rank, 2, i,
2316 0);
2317 failmask |=
2318 check_testing_type2(info, total_rank, 3, i,
2319 1);
2320 }
2321
Felix Held04be2dd2018-07-29 04:53:22 +02002322 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002323 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002324 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002325 if ((1 << lane) & failmask) {
2326 if (timings[reg_178][channel]
2327 [slot][rank][lane].
2328 largest <=
2329 timings[reg_178][channel]
2330 [slot][rank][lane].
2331 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002332 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002333 [lane] = -1;
2334 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002335 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002336 [lane] = 0;
2337 timings[reg_178]
2338 [channel][slot]
2339 [rank][lane].
2340 largest--;
2341 write_500(info, channel,
2342 timings
2343 [reg_178]
2344 [channel]
2345 [slot][rank]
2346 [lane].
2347 largest,
2348 get_timing_register_addr
2349 (lane, 0,
2350 slot, rank),
2351 9, 1);
2352 write_500(info, channel,
2353 timings
2354 [reg_178]
2355 [channel]
2356 [slot][rank]
2357 [lane].
2358 largest +
2359 info->
2360 training.
2361 lane_timings
2362 [1][channel]
2363 [slot][rank]
2364 [lane]
2365 -
2366 info->
2367 training.
2368 lane_timings
2369 [0][channel]
2370 [slot][rank]
2371 [lane],
2372 get_timing_register_addr
2373 (lane, 1,
2374 slot, rank),
2375 9, 1);
2376 }
2377 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002378 num_successfully_checked[lane]
2379 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380 }
2381 }
2382 }
Felix Held04be2dd2018-07-29 04:53:22 +02002383 while (!check_bounded(num_successfully_checked, 3))
2384 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002385
2386 for (lane = 0; lane < 8; lane++) {
2387 write_500(info, channel,
2388 info->training.
2389 lane_timings[0][channel][slot][rank][lane],
2390 get_timing_register_addr(lane, 0, slot, rank),
2391 9, 1);
2392 write_500(info, channel,
2393 info->training.
2394 lane_timings[1][channel][slot][rank][lane],
2395 get_timing_register_addr(lane, 1, slot, rank),
2396 9, 1);
2397 if (timings[reg_178][channel][slot][rank][lane].
2398 largest <=
2399 timings[reg_178][channel][slot][rank][lane].
2400 smallest) {
2401 timings[reg_178][channel][slot][rank][lane].
2402 largest = 0;
2403 timings[reg_178][channel][slot][rank][lane].
2404 smallest = 0;
2405 }
2406 }
2407 }
2408}
2409
2410static void set_10b(struct raminfo *info, u8 val)
2411{
2412 int channel;
2413 int slot, rank;
2414 int lane;
2415
2416 if (read_1d0(0x10b, 6) == val)
2417 return;
2418
2419 write_1d0(val, 0x10b, 6, 1);
2420
2421 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2422 u16 reg_500;
2423 reg_500 = read_500(info, channel,
2424 get_timing_register_addr(lane, 0, slot,
2425 rank), 9);
2426 if (val == 1) {
2427 if (lut16[info->clock_speed_index] <= reg_500)
2428 reg_500 -= lut16[info->clock_speed_index];
2429 else
2430 reg_500 = 0;
2431 } else {
2432 reg_500 += lut16[info->clock_speed_index];
2433 }
2434 write_500(info, channel, reg_500,
2435 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2436 }
2437}
2438
2439static void set_ecc(int onoff)
2440{
2441 int channel;
2442 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2443 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002444 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002445 if (onoff)
2446 t |= 1;
2447 else
2448 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002449 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002450 }
2451}
2452
2453static void set_178(u8 val)
2454{
2455 if (val >= 31)
2456 val = val - 31;
2457 else
2458 val = 63 - val;
2459
2460 write_1d0(2 * val, 0x178, 7, 1);
2461}
2462
2463static void
2464write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2465 int type)
2466{
2467 int lane;
2468
2469 for (lane = 0; lane < 8; lane++)
2470 write_500(info, channel,
2471 info->training.
2472 lane_timings[type][channel][slot][rank][lane],
2473 get_timing_register_addr(lane, type, slot, rank), 9,
2474 0);
2475}
2476
2477static void
2478try_timing_offsets(struct raminfo *info, int channel,
2479 int slot, int rank, int totalrank)
2480{
2481 u16 count[8];
2482 enum state state[8];
2483 u8 lower_usable[8], upper_usable[8];
2484 int lane;
2485 int i;
2486 int flip = 1;
2487 int timing_offset;
2488
2489 for (i = 0; i < 8; i++)
2490 state[i] = BEFORE_USABLE;
2491
2492 memset(count, 0, sizeof(count));
2493
2494 for (lane = 0; lane < 8; lane++)
2495 write_500(info, channel,
2496 info->training.
2497 lane_timings[2][channel][slot][rank][lane] + 32,
2498 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2499
2500 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2501 timing_offset++) {
2502 u8 failmask;
2503 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2504 failmask = 0;
2505 for (i = 0; i < 2 && failmask != 0xff; i++) {
2506 flip = !flip;
2507 write_testing(info, totalrank, flip);
2508 failmask |= check_testing(info, totalrank, flip);
2509 }
2510 do_fsm(state, count, failmask, 10, 63, lower_usable,
2511 upper_usable, timing_offset);
2512 }
2513 write_1d0(0, 0x1bb, 6, 1);
2514 dump_timings(info);
2515 if (!validate_state(state))
2516 die("Couldn't discover DRAM timings (1)\n");
2517
2518 for (lane = 0; lane < 8; lane++) {
2519 u8 bias = 0;
2520
2521 if (info->silicon_revision) {
2522 int usable_length;
2523
2524 usable_length = upper_usable[lane] - lower_usable[lane];
2525 if (usable_length >= 20) {
2526 bias = usable_length / 2 - 10;
2527 if (bias >= 2)
2528 bias = 2;
2529 }
2530 }
2531 write_500(info, channel,
2532 info->training.
2533 lane_timings[2][channel][slot][rank][lane] +
2534 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2535 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2536 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2537 info->training.lane_timings[2][channel][slot][rank][lane] +
2538 lower_usable[lane];
2539 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2540 info->training.lane_timings[2][channel][slot][rank][lane] +
2541 upper_usable[lane];
2542 info->training.timing2_offset[channel][slot][rank][lane] =
2543 info->training.lane_timings[2][channel][slot][rank][lane];
2544 }
2545}
2546
2547static u8
2548choose_training(struct raminfo *info, int channel, int slot, int rank,
2549 int lane, timing_bounds_t * timings, u8 center_178)
2550{
2551 u16 central_weight;
2552 u16 side_weight;
2553 unsigned int sum = 0, count = 0;
2554 u8 span;
2555 u8 lower_margin, upper_margin;
2556 u8 reg_178;
2557 u8 result;
2558
2559 span = 12;
2560 central_weight = 20;
2561 side_weight = 20;
2562 if (info->silicon_revision == 1 && channel == 1) {
2563 central_weight = 5;
2564 side_weight = 20;
2565 if ((info->
2566 populated_ranks_mask[1] ^ (info->
2567 populated_ranks_mask[1] >> 2)) &
2568 1)
2569 span = 18;
2570 }
2571 if ((info->populated_ranks_mask[0] & 5) == 5) {
2572 central_weight = 20;
2573 side_weight = 20;
2574 }
2575 if (info->clock_speed_index >= 2
2576 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2577 if (info->silicon_revision == 1) {
2578 switch (channel) {
2579 case 0:
2580 if (lane == 1) {
2581 central_weight = 10;
2582 side_weight = 20;
2583 }
2584 break;
2585 case 1:
2586 if (lane == 6) {
2587 side_weight = 5;
2588 central_weight = 20;
2589 }
2590 break;
2591 }
2592 }
2593 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2594 side_weight = 5;
2595 central_weight = 20;
2596 }
2597 }
2598 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2599 reg_178 += span) {
2600 u8 smallest;
2601 u8 largest;
2602 largest = timings[reg_178][channel][slot][rank][lane].largest;
2603 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2604 if (largest - smallest + 1 >= 5) {
2605 unsigned int weight;
2606 if (reg_178 == center_178)
2607 weight = central_weight;
2608 else
2609 weight = side_weight;
2610 sum += weight * (largest + smallest);
2611 count += weight;
2612 }
2613 }
2614 dump_timings(info);
2615 if (count == 0)
2616 die("Couldn't discover DRAM timings (2)\n");
2617 result = sum / (2 * count);
2618 lower_margin =
2619 result - timings[center_178][channel][slot][rank][lane].smallest;
2620 upper_margin =
2621 timings[center_178][channel][slot][rank][lane].largest - result;
2622 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002623 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002624 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002625 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002626 return result;
2627}
2628
2629#define STANDARD_MIN_MARGIN 5
2630
2631static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2632{
2633 u16 margin[64];
2634 int lane, rank, slot, channel;
2635 u8 reg178;
2636 int count = 0, sum = 0;
2637
2638 for (reg178 = reg178_min[info->clock_speed_index];
2639 reg178 < reg178_max[info->clock_speed_index];
2640 reg178 += reg178_step[info->clock_speed_index]) {
2641 margin[reg178] = -1;
2642 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2643 int curmargin =
2644 timings[reg178][channel][slot][rank][lane].largest -
2645 timings[reg178][channel][slot][rank][lane].
2646 smallest + 1;
2647 if (curmargin < margin[reg178])
2648 margin[reg178] = curmargin;
2649 }
2650 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2651 u16 weight;
2652 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2653 sum += weight * reg178;
2654 count += weight;
2655 }
2656 }
2657 dump_timings(info);
2658 if (count == 0)
2659 die("Couldn't discover DRAM timings (3)\n");
2660
2661 u8 threshold;
2662
2663 for (threshold = 30; threshold >= 5; threshold--) {
2664 int usable_length = 0;
2665 int smallest_fount = 0;
2666 for (reg178 = reg178_min[info->clock_speed_index];
2667 reg178 < reg178_max[info->clock_speed_index];
2668 reg178 += reg178_step[info->clock_speed_index])
2669 if (margin[reg178] >= threshold) {
2670 usable_length +=
2671 reg178_step[info->clock_speed_index];
2672 info->training.reg178_largest =
2673 reg178 -
2674 2 * reg178_step[info->clock_speed_index];
2675
2676 if (!smallest_fount) {
2677 smallest_fount = 1;
2678 info->training.reg178_smallest =
2679 reg178 +
2680 reg178_step[info->
2681 clock_speed_index];
2682 }
2683 }
2684 if (usable_length >= 0x21)
2685 break;
2686 }
2687
2688 return sum / count;
2689}
2690
2691static int check_cached_sanity(struct raminfo *info)
2692{
2693 int lane;
2694 int slot, rank;
2695 int channel;
2696
2697 if (!info->cached_training)
2698 return 0;
2699
2700 for (channel = 0; channel < NUM_CHANNELS; channel++)
2701 for (slot = 0; slot < NUM_SLOTS; slot++)
2702 for (rank = 0; rank < NUM_RANKS; rank++)
2703 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2704 u16 cached_value, estimation_value;
2705 cached_value =
2706 info->cached_training->
2707 lane_timings[1][channel][slot][rank]
2708 [lane];
2709 if (cached_value >= 0x18
2710 && cached_value <= 0x1E7) {
2711 estimation_value =
2712 info->training.
2713 lane_timings[1][channel]
2714 [slot][rank][lane];
2715 if (estimation_value <
2716 cached_value - 24)
2717 return 0;
2718 if (estimation_value >
2719 cached_value + 24)
2720 return 0;
2721 }
2722 }
2723 return 1;
2724}
2725
2726static int try_cached_training(struct raminfo *info)
2727{
2728 u8 saved_243[2];
2729 u8 tm;
2730
2731 int channel, slot, rank, lane;
2732 int flip = 1;
2733 int i, j;
2734
2735 if (!check_cached_sanity(info))
2736 return 0;
2737
2738 info->training.reg178_center = info->cached_training->reg178_center;
2739 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2740 info->training.reg178_largest = info->cached_training->reg178_largest;
2741 memcpy(&info->training.timing_bounds,
2742 &info->cached_training->timing_bounds,
2743 sizeof(info->training.timing_bounds));
2744 memcpy(&info->training.timing_offset,
2745 &info->cached_training->timing_offset,
2746 sizeof(info->training.timing_offset));
2747
2748 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002749 saved_243[0] = MCHBAR8(0x243);
2750 saved_243[1] = MCHBAR8(0x643);
2751 MCHBAR8(0x243) = saved_243[0] | 2;
2752 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002753 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002754 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002755 if (read_1d0(0x10b, 6) & 1)
2756 set_10b(info, 0);
2757 for (tm = 0; tm < 2; tm++) {
2758 int totalrank;
2759
2760 set_178(tm ? info->cached_training->reg178_largest : info->
2761 cached_training->reg178_smallest);
2762
2763 totalrank = 0;
2764 /* Check timing ranges. With i == 0 we check smallest one and with
2765 i == 1 the largest bound. With j == 0 we check that on the bound
2766 it still works whereas with j == 1 we check that just outside of
2767 bound we fail.
2768 */
2769 FOR_POPULATED_RANKS_BACKWARDS {
2770 for (i = 0; i < 2; i++) {
2771 for (lane = 0; lane < 8; lane++) {
2772 write_500(info, channel,
2773 info->cached_training->
2774 timing2_bounds[channel][slot]
2775 [rank][lane][i],
2776 get_timing_register_addr(lane,
2777 3,
2778 slot,
2779 rank),
2780 9, 1);
2781
2782 if (!i)
2783 write_500(info, channel,
2784 info->
2785 cached_training->
2786 timing2_offset
2787 [channel][slot][rank]
2788 [lane],
2789 get_timing_register_addr
2790 (lane, 2, slot, rank),
2791 9, 1);
2792 write_500(info, channel,
2793 i ? info->cached_training->
2794 timing_bounds[tm][channel]
2795 [slot][rank][lane].
2796 largest : info->
2797 cached_training->
2798 timing_bounds[tm][channel]
2799 [slot][rank][lane].smallest,
2800 get_timing_register_addr(lane,
2801 0,
2802 slot,
2803 rank),
2804 9, 1);
2805 write_500(info, channel,
2806 info->cached_training->
2807 timing_offset[channel][slot]
2808 [rank][lane] +
2809 (i ? info->cached_training->
2810 timing_bounds[tm][channel]
2811 [slot][rank][lane].
2812 largest : info->
2813 cached_training->
2814 timing_bounds[tm][channel]
2815 [slot][rank][lane].
2816 smallest) - 64,
2817 get_timing_register_addr(lane,
2818 1,
2819 slot,
2820 rank),
2821 9, 1);
2822 }
2823 for (j = 0; j < 2; j++) {
2824 u8 failmask;
2825 u8 expected_failmask;
2826 char reg1b3;
2827
2828 reg1b3 = (j == 1) + 4;
2829 reg1b3 =
2830 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2831 write_1d0(reg1b3, 0x1bb, 6, 1);
2832 write_1d0(reg1b3, 0x1b3, 6, 1);
2833 write_1d0(reg1b3, 0x1a3, 6, 1);
2834
2835 flip = !flip;
2836 write_testing(info, totalrank, flip);
2837 failmask =
2838 check_testing(info, totalrank,
2839 flip);
2840 expected_failmask =
2841 j == 0 ? 0x00 : 0xff;
2842 if (failmask != expected_failmask)
2843 goto fail;
2844 }
2845 }
2846 totalrank++;
2847 }
2848 }
2849
2850 set_178(info->cached_training->reg178_center);
2851 if (info->use_ecc)
2852 set_ecc(1);
2853 write_training_data(info);
2854 write_1d0(0, 322, 3, 1);
2855 info->training = *info->cached_training;
2856
2857 write_1d0(0, 0x1bb, 6, 1);
2858 write_1d0(0, 0x1b3, 6, 1);
2859 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002860 MCHBAR8(0x243) = saved_243[0];
2861 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002862
2863 return 1;
2864
2865fail:
2866 FOR_POPULATED_RANKS {
2867 write_500_timings_type(info, channel, slot, rank, 1);
2868 write_500_timings_type(info, channel, slot, rank, 2);
2869 write_500_timings_type(info, channel, slot, rank, 3);
2870 }
2871
2872 write_1d0(0, 0x1bb, 6, 1);
2873 write_1d0(0, 0x1b3, 6, 1);
2874 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002875 MCHBAR8(0x243) = saved_243[0];
2876 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002877
2878 return 0;
2879}
2880
2881static void do_ram_training(struct raminfo *info)
2882{
2883 u8 saved_243[2];
2884 int totalrank = 0;
2885 u8 reg_178;
2886 int niter;
2887
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002888 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002889 int lane, rank, slot, channel;
2890 u8 reg178_center;
2891
2892 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002893 saved_243[0] = MCHBAR8(0x243);
2894 saved_243[1] = MCHBAR8(0x643);
2895 MCHBAR8(0x243) = saved_243[0] | 2;
2896 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002897 switch (info->clock_speed_index) {
2898 case 0:
2899 niter = 5;
2900 break;
2901 case 1:
2902 niter = 10;
2903 break;
2904 default:
2905 niter = 19;
2906 break;
2907 }
2908 set_ecc(0);
2909
2910 FOR_POPULATED_RANKS_BACKWARDS {
2911 int i;
2912
2913 write_500_timings_type(info, channel, slot, rank, 0);
2914
2915 write_testing(info, totalrank, 0);
2916 for (i = 0; i < niter; i++) {
2917 write_testing_type2(info, totalrank, 2, i, 0);
2918 write_testing_type2(info, totalrank, 3, i, 1);
2919 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002920 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002921 totalrank++;
2922 }
2923
2924 if (reg178_min[info->clock_speed_index] <
2925 reg178_max[info->clock_speed_index])
2926 memset(timings[reg178_min[info->clock_speed_index]], 0,
2927 sizeof(timings[0]) *
2928 (reg178_max[info->clock_speed_index] -
2929 reg178_min[info->clock_speed_index]));
2930 for (reg_178 = reg178_min[info->clock_speed_index];
2931 reg_178 < reg178_max[info->clock_speed_index];
2932 reg_178 += reg178_step[info->clock_speed_index]) {
2933 totalrank = 0;
2934 set_178(reg_178);
2935 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2936 for (slot = 0; slot < NUM_SLOTS; slot++)
2937 for (rank = 0; rank < NUM_RANKS; rank++) {
2938 memset(&timings[reg_178][channel][slot]
2939 [rank][0].smallest, 0, 16);
2940 if (info->
2941 populated_ranks[channel][slot]
2942 [rank]) {
2943 train_ram_at_178(info, channel,
2944 slot, rank,
2945 totalrank,
2946 reg_178, 1,
2947 niter,
2948 timings);
2949 totalrank++;
2950 }
2951 }
2952 }
2953
2954 reg178_center = choose_reg178(info, timings);
2955
2956 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2957 info->training.timing_bounds[0][channel][slot][rank][lane].
2958 smallest =
2959 timings[info->training.
2960 reg178_smallest][channel][slot][rank][lane].
2961 smallest;
2962 info->training.timing_bounds[0][channel][slot][rank][lane].
2963 largest =
2964 timings[info->training.
2965 reg178_smallest][channel][slot][rank][lane].largest;
2966 info->training.timing_bounds[1][channel][slot][rank][lane].
2967 smallest =
2968 timings[info->training.
2969 reg178_largest][channel][slot][rank][lane].smallest;
2970 info->training.timing_bounds[1][channel][slot][rank][lane].
2971 largest =
2972 timings[info->training.
2973 reg178_largest][channel][slot][rank][lane].largest;
2974 info->training.timing_offset[channel][slot][rank][lane] =
2975 info->training.lane_timings[1][channel][slot][rank][lane]
2976 -
2977 info->training.lane_timings[0][channel][slot][rank][lane] +
2978 64;
2979 }
2980
2981 if (info->silicon_revision == 1
2982 && (info->
2983 populated_ranks_mask[1] ^ (info->
2984 populated_ranks_mask[1] >> 2)) & 1) {
2985 int ranks_after_channel1;
2986
2987 totalrank = 0;
2988 for (reg_178 = reg178_center - 18;
2989 reg_178 <= reg178_center + 18; reg_178 += 18) {
2990 totalrank = 0;
2991 set_178(reg_178);
2992 for (slot = 0; slot < NUM_SLOTS; slot++)
2993 for (rank = 0; rank < NUM_RANKS; rank++) {
2994 if (info->
2995 populated_ranks[1][slot][rank]) {
2996 train_ram_at_178(info, 1, slot,
2997 rank,
2998 totalrank,
2999 reg_178, 0,
3000 niter,
3001 timings);
3002 totalrank++;
3003 }
3004 }
3005 }
3006 ranks_after_channel1 = totalrank;
3007
3008 for (reg_178 = reg178_center - 12;
3009 reg_178 <= reg178_center + 12; reg_178 += 12) {
3010 totalrank = ranks_after_channel1;
3011 set_178(reg_178);
3012 for (slot = 0; slot < NUM_SLOTS; slot++)
3013 for (rank = 0; rank < NUM_RANKS; rank++)
3014 if (info->
3015 populated_ranks[0][slot][rank]) {
3016 train_ram_at_178(info, 0, slot,
3017 rank,
3018 totalrank,
3019 reg_178, 0,
3020 niter,
3021 timings);
3022 totalrank++;
3023 }
3024
3025 }
3026 } else {
3027 for (reg_178 = reg178_center - 12;
3028 reg_178 <= reg178_center + 12; reg_178 += 12) {
3029 totalrank = 0;
3030 set_178(reg_178);
3031 FOR_POPULATED_RANKS_BACKWARDS {
3032 train_ram_at_178(info, channel, slot, rank,
3033 totalrank, reg_178, 0, niter,
3034 timings);
3035 totalrank++;
3036 }
3037 }
3038 }
3039
3040 set_178(reg178_center);
3041 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3042 u16 tm0;
3043
3044 tm0 =
3045 choose_training(info, channel, slot, rank, lane, timings,
3046 reg178_center);
3047 write_500(info, channel, tm0,
3048 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3049 write_500(info, channel,
3050 tm0 +
3051 info->training.
3052 lane_timings[1][channel][slot][rank][lane] -
3053 info->training.
3054 lane_timings[0][channel][slot][rank][lane],
3055 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3056 }
3057
3058 totalrank = 0;
3059 FOR_POPULATED_RANKS_BACKWARDS {
3060 try_timing_offsets(info, channel, slot, rank, totalrank);
3061 totalrank++;
3062 }
Felix Held04be2dd2018-07-29 04:53:22 +02003063 MCHBAR8(0x243) = saved_243[0];
3064 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003065 write_1d0(0, 0x142, 3, 1);
3066 info->training.reg178_center = reg178_center;
3067}
3068
3069static void ram_training(struct raminfo *info)
3070{
3071 u16 saved_fc4;
3072
Felix Held04be2dd2018-07-29 04:53:22 +02003073 saved_fc4 = MCHBAR16(0xfc4);
3074 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003075
3076 if (info->revision >= 8)
3077 read_4090(info);
3078
3079 if (!try_cached_training(info))
3080 do_ram_training(info);
3081 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3082 && info->clock_speed_index < 2)
3083 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003084 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003085}
3086
Angel Pons7a87c922021-01-15 22:50:41 +01003087u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003088{
3089 int slot, rank, lane;
3090 u16 ret = 0;
3091
Felix Held04be2dd2018-07-29 04:53:22 +02003092 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003093 return 384;
3094
3095 if (info->revision < 8)
3096 return 256;
3097
3098 for (slot = 0; slot < NUM_SLOTS; slot++)
3099 for (rank = 0; rank < NUM_RANKS; rank++)
3100 if (info->populated_ranks[channel][slot][rank])
3101 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003102 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003103 get_timing_register_addr
3104 (lane, 0, slot,
3105 rank), 9));
3106 return ret;
3107}
3108
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003109static void dmi_setup(void)
3110{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003111 gav(DMIBAR8(0x254));
3112 DMIBAR8(0x254) = 0x1;
3113 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003114 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003115
Angel Ponsd071c4d2020-09-14 23:51:35 +02003116 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003117
3118 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3119 DEFAULT_GPIOBASE | 0x38);
3120 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3121}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003122
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003123void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003124{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003125 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003126 u16 ggc;
3127 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003128
Felix Held04be2dd2018-07-29 04:53:22 +02003129 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003130 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3131 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003132 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003133 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003134 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003135
3136 dmi_setup();
3137
Felix Held04be2dd2018-07-29 04:53:22 +02003138 MCHBAR16(0x1170) = 0xa880;
3139 MCHBAR8(0x11c1) = 0x1;
3140 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003141 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003142
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003143 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3144 /* 0 for 32MB */
3145 gfxsize = 0;
3146 }
3147
3148 ggc = 0xb00 | ((gfxsize + 5) << 4);
3149
Angel Pons16fe1e02020-07-22 16:12:33 +02003150 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003151
3152 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003153 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003154
3155 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003156 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003157 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003158 MCHBAR16_OR(0x2c30, 0x200);
3159 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003160 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003161 pci_read_config8(GMA, MSAC); // = 0x2
3162 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003163 RCBA8(0x2318);
3164 RCBA8(0x2318) = 0x47;
3165 RCBA8(0x2320);
3166 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003167 }
3168
Felix Heldf83d80b2018-07-29 05:30:30 +02003169 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003170
Angel Pons16fe1e02020-07-22 16:12:33 +02003171 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003172 gav(RCBA32(0x3428));
3173 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003174}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003175
Angel Pons26681912021-01-15 21:36:28 +01003176static u8 get_bits_420(const u32 reg32)
3177{
3178 u8 val = 0;
3179 val |= (reg32 >> 4) & (1 << 0);
3180 val |= (reg32 >> 2) & (1 << 1);
3181 val |= (reg32 >> 0) & (1 << 2);
3182 return val;
3183}
3184
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003185void raminit(const int s3resume, const u8 *spd_addrmap)
3186{
Martin Roth468d02c2019-10-23 21:44:42 -06003187 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003188 struct raminfo info;
3189 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003190 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003191
Felix Held04be2dd2018-07-29 04:53:22 +02003192 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003193
3194 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3195
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003196 memset(&info, 0x5a, sizeof(info));
3197
3198 info.last_500_command[0] = 0;
3199 info.last_500_command[1] = 0;
3200
3201 info.fsb_frequency = 135 * 2;
3202 info.board_lane_delay[0] = 0x14;
3203 info.board_lane_delay[1] = 0x07;
3204 info.board_lane_delay[2] = 0x07;
3205 info.board_lane_delay[3] = 0x08;
3206 info.board_lane_delay[4] = 0x56;
3207 info.board_lane_delay[5] = 0x04;
3208 info.board_lane_delay[6] = 0x04;
3209 info.board_lane_delay[7] = 0x05;
3210 info.board_lane_delay[8] = 0x10;
3211
3212 info.training.reg_178 = 0;
3213 info.training.reg_10b = 0;
3214
Angel Ponsa3868292021-01-15 22:10:13 +01003215 /* Wait for some bit, maybe TXT clear. */
3216 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3217 ;
3218
3219 /* Wait for ME to be ready */
Angel Pons44479962021-02-24 23:08:27 +01003220 if (intel_early_me_init() == 0)
3221 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
3222 else
3223 info.memory_reserved_for_heci_mb = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003224
3225 /* before SPD */
3226 timestamp_add_now(101);
3227
Felix Held29a9c072018-07-29 01:34:45 +02003228 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003229 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3230
3231 info.use_ecc = 1;
3232 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003233 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003234 int v;
3235 int try;
3236 int addr;
3237 const u8 useful_addresses[] = {
3238 DEVICE_TYPE,
3239 MODULE_TYPE,
3240 DENSITY,
3241 RANKS_AND_DQ,
3242 MEMORY_BUS_WIDTH,
3243 TIMEBASE_DIVIDEND,
3244 TIMEBASE_DIVISOR,
3245 CYCLETIME,
3246 CAS_LATENCIES_LSB,
3247 CAS_LATENCIES_MSB,
3248 CAS_LATENCY_TIME,
3249 0x11, 0x12, 0x13, 0x14, 0x15,
3250 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3251 0x1c, 0x1d,
3252 THERMAL_AND_REFRESH,
3253 0x20,
3254 REFERENCE_RAW_CARD_USED,
3255 RANK1_ADDRESS_MAPPING,
3256 0x75, 0x76, 0x77, 0x78,
3257 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3258 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3259 0x85, 0x86, 0x87, 0x88,
3260 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3261 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3262 0x95
3263 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003264 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003265 continue;
3266 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003267 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003268 DEVICE_TYPE);
3269 if (v >= 0)
3270 break;
3271 }
3272 if (v < 0)
3273 continue;
3274 for (addr = 0;
3275 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003276 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003277 gav(info.
3278 spd[channel][0][useful_addresses
3279 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003280 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003281 useful_addresses
3282 [addr]));
3283 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3284 die("Only DDR3 is supported");
3285
3286 v = info.spd[channel][0][RANKS_AND_DQ];
3287 info.populated_ranks[channel][0][0] = 1;
3288 info.populated_ranks[channel][0][1] =
3289 ((v >> 3) & 7);
3290 if (((v >> 3) & 7) > 1)
3291 die("At most 2 ranks are supported");
3292 if ((v & 7) == 0 || (v & 7) > 2)
3293 die("Only x8 and x16 modules are supported");
3294 if ((info.
3295 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3296 && (info.
3297 spd[channel][slot][MODULE_TYPE] & 0xF)
3298 != 3)
3299 die("Registered memory is not supported");
3300 info.is_x16_module[channel][0] = (v & 7) - 1;
3301 info.density[channel][slot] =
3302 info.spd[channel][slot][DENSITY] & 0xF;
3303 if (!
3304 (info.
3305 spd[channel][slot][MEMORY_BUS_WIDTH] &
3306 0x18))
3307 info.use_ecc = 0;
3308 }
3309
3310 gav(0x55);
3311
3312 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3313 int v = 0;
3314 for (slot = 0; slot < NUM_SLOTS; slot++)
3315 for (rank = 0; rank < NUM_RANKS; rank++)
3316 v |= info.
3317 populated_ranks[channel][slot][rank]
3318 << (2 * slot + rank);
3319 info.populated_ranks_mask[channel] = v;
3320 }
3321
3322 gav(0x55);
3323
Angel Pons16fe1e02020-07-22 16:12:33 +02003324 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003325 }
3326
3327 /* after SPD */
3328 timestamp_add_now(102);
3329
Felix Held04be2dd2018-07-29 04:53:22 +02003330 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003331
3332 collect_system_info(&info);
3333 calculate_timings(&info);
3334
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003335 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003336 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003337 if (x2ca8 == 0 && (reg8 & 0x80)) {
3338 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3339 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3340 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3341 */
3342
3343 /* Clear bit7. */
3344
3345 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3346 (reg8 & ~(1 << 7)));
3347
3348 printk(BIOS_INFO,
3349 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003350 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003351 }
3352 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003353
3354 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003355 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3356 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003357
3358 compute_derived_timings(&info);
3359
Angel Pons56823f52021-01-16 11:27:33 +01003360 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003361
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003362 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003363
Angel Pons7a87c922021-01-15 22:50:41 +01003364 if (x2ca8 == 0)
3365 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003366
Angel Ponsc627dc92020-09-22 17:06:44 +02003367 MCHBAR32_OR(0x2c80, (1 << 24));
3368 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003369
Angel Ponsc627dc92020-09-22 17:06:44 +02003370 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003371
3372 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003373 MCHBAR8_AND(0x2ca8, ~3);
3374 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003375 /* This issues a CPU reset without resetting the platform */
3376 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003377 /* Write back the S3 state to PM1_CNT to let the reset CPU
3378 know it also needs to take the s3 path. */
3379 if (s3resume)
3380 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3381 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02003382 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01003383 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003384 }
Angel Pons7a87c922021-01-15 22:50:41 +01003385
Angel Ponsc627dc92020-09-22 17:06:44 +02003386 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003387
Angel Ponsc627dc92020-09-22 17:06:44 +02003388 MCHBAR32_AND(0x2c80, ~(1 << 24));
3389
Angel Pons9addda32020-07-22 18:37:32 +02003390 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003391
3392 {
3393 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
3394 u16 x2c10 = MCHBAR16(0x2c10);
3395 u16 value = MCHBAR16(0x2c00);
3396 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3397 value |= (1 << 7);
3398 else
3399 value &= ~(1 << 0);
3400
3401 MCHBAR16(0x2c00) = value;
3402 }
3403
3404 udelay(1000); // !!!!
3405
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406 write_1d0(0, 0x33d, 0, 0);
3407 write_500(&info, 0, 0, 0xb61, 0, 0);
3408 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003409 MCHBAR32(0x1a30) = 0x0;
3410 MCHBAR32(0x1a34) = 0x0;
3411 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3412 (info.populated_ranks[0][0][0] * 0xa0);
3413 MCHBAR16(0x616) = 0x26a;
3414 MCHBAR32(0x134) = 0x856000;
3415 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02003416 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
3417 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003418 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003419 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
3420 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003421 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003422 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02003423 MCHBAR16(0x360 + (channel << 10)) = 0x909;
3424 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02003425 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
3426 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
3427 MCHBAR32(0x324 + (channel << 10)) = 0x0;
3428 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
3429 MCHBAR16(0x352 + (channel << 10)) = 0x505;
3430 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
3431 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
3432 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
3433 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
3434 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 }
3436
3437 write_1d0(0x4, 0x151, 4, 1);
3438 write_1d0(0, 0x142, 3, 1);
3439 rdmsr(0x1ac); // !!!!
3440 write_500(&info, 1, 1, 0x6b3, 4, 1);
3441 write_500(&info, 1, 1, 0x6cf, 4, 1);
3442
Angel Pons244f4552021-01-15 20:41:36 +01003443 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003444
3445 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3446 populated_ranks[0]
3447 [0][0]) << 0),
3448 0x1d1, 3, 1);
3449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003450 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
3451 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003452 }
3453
3454 set_334(0);
3455
3456 program_base_timings(&info);
3457
Felix Held04be2dd2018-07-29 04:53:22 +02003458 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003459
3460 write_1d0(0x2, 0x1d5, 2, 1);
3461 write_1d0(0x20, 0x166, 7, 1);
3462 write_1d0(0x0, 0xeb, 3, 1);
3463 write_1d0(0x0, 0xf3, 6, 1);
3464
Angel Pons3d357562021-01-16 14:46:45 +01003465 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3466 u8 a = 0;
3467 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3468 a = 3;
3469 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3470 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003471
Angel Pons3d357562021-01-16 14:46:45 +01003472 for (lane = 0; lane < 9; lane++) {
3473 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3474 rmw_500(&info, channel, addr, 6, 0xf, a);
3475 }
3476 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003478 if (s3resume) {
3479 if (info.cached_training == NULL) {
3480 u32 reg32;
3481 printk(BIOS_ERR,
3482 "Couldn't find training data. Rebooting\n");
3483 reg32 = inl(DEFAULT_PMBASE + 0x04);
3484 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003485 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003486 }
3487 int tm;
3488 info.training = *info.cached_training;
3489 for (tm = 0; tm < 4; tm++)
3490 for (channel = 0; channel < NUM_CHANNELS; channel++)
3491 for (slot = 0; slot < NUM_SLOTS; slot++)
3492 for (rank = 0; rank < NUM_RANKS; rank++)
3493 for (lane = 0; lane < 9; lane++)
3494 write_500(&info,
3495 channel,
3496 info.training.
3497 lane_timings
3498 [tm][channel]
3499 [slot][rank]
3500 [lane],
3501 get_timing_register_addr
3502 (lane, tm,
3503 slot, rank),
3504 9, 0);
3505 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3506 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3507 }
3508
Felix Heldf83d80b2018-07-29 05:30:30 +02003509 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02003510 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02003511 MCHBAR8_OR(0x1f0, 0x1);
3512 while (MCHBAR8(0x1f0) & 1)
3513 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514
3515 program_board_delay(&info);
3516
Felix Held04be2dd2018-07-29 04:53:22 +02003517 MCHBAR8(0x5ff) = 0x0;
3518 MCHBAR8(0x5ff) = 0x80;
3519 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003520
Felix Held04be2dd2018-07-29 04:53:22 +02003521 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02003522 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003523 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003524
3525 rmw_1d0(0x14b, 0x47, 0x30, 7);
3526 rmw_1d0(0xd6, 0x38, 7, 6);
3527 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003528
3529 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003530 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003531
Angel Ponsc627dc92020-09-22 17:06:44 +02003532 rmw_1d0(0x116, 0xe, 0, 4);
3533 rmw_1d0(0xae, 0x3e, 0, 6);
3534 rmw_1d0(0x300, 0x3e, 0, 6);
3535 MCHBAR16_AND(0x356, 0x7fff);
3536 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02003537 MCHBAR32_AND(0x140, ~0x07000000);
3538 MCHBAR32_AND(0x138, ~0x07000000);
3539 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003540 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02003541 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003542 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003543
Angel Pons26681912021-01-15 21:36:28 +01003544 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003545 {
Angel Pons26681912021-01-15 21:36:28 +01003546 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3547 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3548 value_a1 = val_xa1;
3549 rmw_1d0(0x320, 0x38, val_2f3, 6);
3550 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3551 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003552 }
3553
3554 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003555 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003556
Angel Pons244f4552021-01-15 20:41:36 +01003557 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003558 {
3559 if ((MCHBAR32(0x144) & 0x1f) < 0x13)
3560 value_a1 += 2;
3561 else
3562 value_a1 += 1;
3563
3564 if (value_a1 > 7)
3565 value_a1 = 7;
3566
3567 write_1d0(2, 0xae, 6, 1);
3568 write_1d0(2, 0x300, 6, 1);
3569 write_1d0(value_a1, 0x121, 3, 1);
3570 rmw_1d0(0xd6, 0x38, 4, 6);
3571 rmw_1d0(0x328, 0x38, 4, 6);
3572 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003573
3574 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003575 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003576
Felix Held04be2dd2018-07-29 04:53:22 +02003577 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
3578 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02003579 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003580 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003581
3582 {
Angel Pons26681912021-01-15 21:36:28 +01003583 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003584 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3585 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003586 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003587 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003588
3589 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003590 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003591
3592 set_334(1);
3593
Felix Held04be2dd2018-07-29 04:53:22 +02003594 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595
3596 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3597 write_500(&info, channel,
3598 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3599 1);
3600 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3601 }
Felix Held04be2dd2018-07-29 04:53:22 +02003602 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
3603 MCHBAR16(0x6c0) = 0x14a0;
3604 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
3605 MCHBAR16(0x232) = 0x8;
3606 /* 0x40004 or 0 depending on ? */
3607 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
3608 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
3609 MCHBAR32(0x128) = 0x2150d05;
3610 MCHBAR8(0x12c) = 0x1f;
3611 MCHBAR8(0x12d) = 0x56;
3612 MCHBAR8(0x12e) = 0x31;
3613 MCHBAR8(0x12f) = 0x0;
3614 MCHBAR8(0x271) = 0x2;
3615 MCHBAR8(0x671) = 0x2;
3616 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003618 MCHBAR32(0x294 + (channel << 10)) =
3619 (info.populated_ranks_mask[channel] & 3) << 16;
3620 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
3621 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02003623 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
3624 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625
3626 if (!s3resume)
3627 jedec_init(&info);
3628
3629 int totalrank = 0;
3630 for (channel = 0; channel < NUM_CHANNELS; channel++)
3631 for (slot = 0; slot < NUM_SLOTS; slot++)
3632 for (rank = 0; rank < NUM_RANKS; rank++)
3633 if (info.populated_ranks[channel][slot][rank]) {
3634 jedec_read(&info, channel, slot, rank,
3635 totalrank, 0xa, 0x400);
3636 totalrank++;
3637 }
3638
Felix Held04be2dd2018-07-29 04:53:22 +02003639 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640
Angel Ponsc627dc92020-09-22 17:06:44 +02003641 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
3642 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643
3644 if (!s3resume) {
3645 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003646 MCHBAR32(0x294 + (channel << 10)) =
3647 (info.populated_ranks_mask[channel] & 3) << 16;
3648 MCHBAR16(0x298 + (channel << 10)) =
3649 info.populated_ranks[channel][0][0] |
3650 (info.populated_ranks[channel][0][1] << 5);
3651 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003653 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654
3655 {
3656 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02003657 a = MCHBAR8(0x243);
3658 b = MCHBAR8(0x643);
3659 MCHBAR8(0x243) = a | 2;
3660 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661 }
3662
3663 write_1d0(7, 0x19b, 3, 1);
3664 write_1d0(7, 0x1c0, 3, 1);
3665 write_1d0(4, 0x1c6, 4, 1);
3666 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003667 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02003668 MCHBAR32(0x584) = 0xfffff;
3669 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670
3671 for (channel = 0; channel < NUM_CHANNELS; channel++)
3672 for (slot = 0; slot < NUM_SLOTS; slot++)
3673 for (rank = 0; rank < NUM_RANKS; rank++)
3674 if (info.
3675 populated_ranks[channel][slot]
3676 [rank])
3677 config_rank(&info, s3resume,
3678 channel, slot,
3679 rank);
3680
Felix Held04be2dd2018-07-29 04:53:22 +02003681 MCHBAR8(0x243) = 0x1;
3682 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683 }
3684
3685 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003686 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003687 write_26c(0, 0x820);
3688 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02003689 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690 /* end */
3691
3692 if (s3resume) {
3693 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003694 MCHBAR32(0x294 + (channel << 10)) =
3695 (info.populated_ranks_mask[channel] & 3) << 16;
3696 MCHBAR16(0x298 + (channel << 10)) =
3697 info.populated_ranks[channel][0][0] |
3698 (info.populated_ranks[channel][0][1] << 5);
3699 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003701 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003702 }
3703
Felix Held04be2dd2018-07-29 04:53:22 +02003704 MCHBAR32_AND(0xfa4, ~0x01000002);
3705 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003707 /* Before training. */
3708 timestamp_add_now(103);
3709
3710 if (!s3resume)
3711 ram_training(&info);
3712
3713 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003714 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715
3716 dump_timings(&info);
3717
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718 program_modules_memory_map(&info, 0);
3719 program_total_memory_map(&info);
3720
3721 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02003722 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02003724 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02003726 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727 else
Felix Held04be2dd2018-07-29 04:53:22 +02003728 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003729
Felix Held04be2dd2018-07-29 04:53:22 +02003730 MCHBAR32_AND(0xfac, ~0x80000000);
3731 MCHBAR32(0xfb4) = 0x4800;
3732 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
3733 MCHBAR32(0xe94) = 0x7ffff;
3734 MCHBAR32(0xfc0) = 0x80002040;
3735 MCHBAR32(0xfc4) = 0x701246;
3736 MCHBAR8_AND(0xfc8, ~0x70);
3737 MCHBAR32_OR(0xe5c, 0x1000000);
3738 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
3739 MCHBAR32(0x50) = 0x700b0;
3740 MCHBAR32(0x3c) = 0x10;
3741 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
3742 MCHBAR8_OR(0xff4, 0x2);
3743 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003744
Felix Held04be2dd2018-07-29 04:53:22 +02003745 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
3746 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
3747 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003748
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003749 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3750 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3751 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003752
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003753 {
3754 u32 eax;
3755
3756 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02003757 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
3758 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
3759 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003760 }
3761
3762 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003763 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003765 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766 else
Felix Held04be2dd2018-07-29 04:53:22 +02003767 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003768
Felix Held04be2dd2018-07-29 04:53:22 +02003769 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003770
Felix Held04be2dd2018-07-29 04:53:22 +02003771 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003772 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02003773 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003774 else
Felix Held04be2dd2018-07-29 04:53:22 +02003775 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003776 }
3777
Felix Held04be2dd2018-07-29 04:53:22 +02003778 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779
3780 {
3781 u8 al;
3782 al = 0xd;
3783 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3784 al += 2;
3785 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02003786 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003787 }
3788
3789 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003790 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
3791 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
3792 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
3793 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003794 }
3795 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003796 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003797 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003798 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003799 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003800 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003801 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02003802 MCHBAR8_OR(0x1210, 2);
3803 MCHBAR32(0x1200) = 0x8800440;
3804 MCHBAR32(0x1204) = 0x53ff0453;
3805 MCHBAR32(0x1208) = 0x19002043;
3806 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003807
3808 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02003809 MCHBAR16(0x1214) = 0x220;
3810 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003811 }
3812
Felix Held04be2dd2018-07-29 04:53:22 +02003813 MCHBAR8_OR(0x1214, 0x4);
3814 MCHBAR8(0x120c) = 0x1;
3815 MCHBAR8(0x1218) = 0x3;
3816 MCHBAR8(0x121a) = 0x3;
3817 MCHBAR8(0x121c) = 0x3;
3818 MCHBAR16(0xc14) = 0x0;
3819 MCHBAR16(0xc20) = 0x0;
3820 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003821
3822 /* revision dependent here. */
3823
Felix Held04be2dd2018-07-29 04:53:22 +02003824 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003825
3826 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02003827 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003828
Felix Held04be2dd2018-07-29 04:53:22 +02003829 MCHBAR16_OR(0x1230, 0x8000);
3830 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003831
3832 u8 bl, ebpb;
3833 u16 reg_1020;
3834
Felix Held04be2dd2018-07-29 04:53:22 +02003835 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
3836 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003837
Felix Held04be2dd2018-07-29 04:53:22 +02003838 MCHBAR32(0x1000) = 0x100;
3839 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840
3841 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003842 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003843 bl = reg_1020 >> 8;
3844 ebpb = reg_1020 & 0xff;
3845 } else {
3846 ebpb = 0;
3847 bl = 8;
3848 }
3849
3850 rdmsr(0x1a2);
3851
Felix Held04be2dd2018-07-29 04:53:22 +02003852 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003853
Felix Held04be2dd2018-07-29 04:53:22 +02003854 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855
Felix Held04be2dd2018-07-29 04:53:22 +02003856 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003857
Felix Held04be2dd2018-07-29 04:53:22 +02003858 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003860 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
3861 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862 }
3863
3864 setup_heci_uma(&info);
3865
3866 if (info.uma_enabled) {
3867 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02003868 MCHBAR32_OR(0x11b0, 0x4000);
3869 MCHBAR32_OR(0x11b4, 0x4000);
3870 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
Felix Held04be2dd2018-07-29 04:53:22 +02003872 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
3873 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
3874 MCHBAR16_OR(0x1170, 0x1000);
3875
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003877
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003878 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02003879 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003880 ;
3881 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003882 }
3883
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003884 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3885 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003886 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02003887 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003888
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889 udelay(1000);
3890 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003891 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3892
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893 if (!s3resume)
3894 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003895 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003896 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003897 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003898
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003899 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003900 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003901 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003902}