blob: af835e285590461ca564c89701d7698669656777 [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
118static void sfence(void)
119{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100120 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100121}
122
123static inline u16 get_lane_offset(int slot, int rank, int lane)
124{
125 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
126 0x452 * (lane == 8);
127}
128
129static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
130{
131 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
132 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
133}
134
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100135static u32 gav_real(int line, u32 in)
136{
137 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
138 return in;
139}
140
141#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200142
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200143/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100144timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200145
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146/* OK */
147static u16
148read_500(struct raminfo *info, int channel, u16 addr, int split)
149{
150 u32 val;
151 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200152 MCHBAR32(0x500 + (channel << 10)) = 0;
153 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
154 ;
155 MCHBAR32(0x500 + (channel << 10)) =
156 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
157 + 0xb88 - addr);
158 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
159 ;
160 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100161 return val & ((1 << split) - 1);
162}
163
164/* OK */
165static void
166write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
167 int flag)
168{
169 if (info->last_500_command[channel] == 0x80000000) {
170 info->last_500_command[channel] = 0x40000000;
171 write_500(info, channel, 0, 0xb61, 0, 0);
172 }
Felix Held04be2dd2018-07-29 04:53:22 +0200173 MCHBAR32(0x500 + (channel << 10)) = 0;
174 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
175 ;
176 MCHBAR32(0x504 + (channel << 10)) =
177 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
178 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200179 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200180 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100181}
182
Angel Ponsc10f8b22021-01-15 20:34:51 +0100183static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
184{
185 const u32 val = read_500(info, channel, addr, bits) & and;
186 write_500(info, channel, val | or, addr, bits, 1);
187}
188
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100189static int rw_test(int rank)
190{
191 const u32 mask = 0xf00fc33c;
192 int ok = 0xff;
193 int i;
194 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800195 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196 sfence();
197 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800198 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100199 sfence();
200 for (i = 0; i < 32; i++) {
201 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800202 write32p((rank << 28) | (i << 3), pat);
203 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100204 }
205 sfence();
206 for (i = 0; i < 32; i++) {
207 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
208 int j;
209 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800210 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100211 for (j = 0; j < 4; j++)
212 if (((val >> (j * 8)) & 0xff) != pat)
213 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800214 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100215 for (j = 0; j < 4; j++)
216 if (((val >> (j * 8)) & 0xff) != pat)
217 ok &= ~(16 << j);
218 }
219 sfence();
220 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800221 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100222 sfence();
223 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800224 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100225
226 return ok;
227}
228
229static void
230program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
231{
232 int lane;
233 for (lane = 0; lane < 8; lane++) {
234 write_500(info, channel,
235 base +
236 info->training.
237 lane_timings[2][channel][slot][rank][lane],
238 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
239 write_500(info, channel,
240 base +
241 info->training.
242 lane_timings[3][channel][slot][rank][lane],
243 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
244 }
245}
246
247static void write_26c(int channel, u16 si)
248{
Felix Held04be2dd2018-07-29 04:53:22 +0200249 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
250 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
251 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100252}
253
Angel Ponsc627dc92020-09-22 17:06:44 +0200254static void toggle_1d0_142_5ff(void)
255{
256 u32 reg32 = gav(read_1d0(0x142, 3));
257 if (reg32 & (1 << 1))
258 write_1d0(0, 0x142, 3, 1);
259
260 MCHBAR8(0x5ff) = 0x0;
261 MCHBAR8(0x5ff) = 0x80;
262 if (reg32 & (1 << 1))
263 write_1d0(0x2, 0x142, 3, 1);
264}
265
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100266static u32 get_580(int channel, u8 addr)
267{
268 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200269 toggle_1d0_142_5ff();
Felix Held04be2dd2018-07-29 04:53:22 +0200270 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
271 MCHBAR8_OR(0x580 + (channel << 10), 1);
272 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
273 ;
274 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100275 return ret;
276}
277
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278#define RANK_SHIFT 28
279#define CHANNEL_SHIFT 10
280
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100281static void seq9(struct raminfo *info, int channel, int slot, int rank)
282{
283 int i, lane;
284
285 for (i = 0; i < 2; i++)
286 for (lane = 0; lane < 8; lane++)
287 write_500(info, channel,
288 info->training.lane_timings[i +
289 1][channel][slot]
290 [rank][lane], get_timing_register_addr(lane,
291 i + 1,
292 slot,
293 rank),
294 9, 0);
295
296 write_1d0(1, 0x103, 6, 1);
297 for (lane = 0; lane < 8; lane++)
298 write_500(info, channel,
299 info->training.
300 lane_timings[0][channel][slot][rank][lane],
301 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
302
303 for (i = 0; i < 2; i++) {
304 for (lane = 0; lane < 8; lane++)
305 write_500(info, channel,
306 info->training.lane_timings[i +
307 1][channel][slot]
308 [rank][lane], get_timing_register_addr(lane,
309 i + 1,
310 slot,
311 rank),
312 9, 0);
313 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
314 }
315
Angel Ponsc627dc92020-09-22 17:06:44 +0200316 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100317 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200318
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100319 for (lane = 0; lane < 8; lane++) {
320 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
321 info->training.lane_timings[2][channel][slot][rank][lane] =
322 read_500(info, channel,
323 get_timing_register_addr(lane, 2, slot, rank), 9);
324 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
325 info->training.lane_timings[3][channel][slot][rank][lane] =
326 info->training.lane_timings[2][channel][slot][rank][lane] +
327 0x20;
328 }
329}
330
331static int count_ranks_in_channel(struct raminfo *info, int channel)
332{
333 int slot, rank;
334 int res = 0;
335 for (slot = 0; slot < NUM_SLOTS; slot++)
336 for (rank = 0; rank < NUM_SLOTS; rank++)
337 res += info->populated_ranks[channel][slot][rank];
338 return res;
339}
340
341static void
342config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
343{
344 int add;
345
346 write_1d0(0, 0x178, 7, 1);
347 seq9(info, channel, slot, rank);
348 program_timings(info, 0x80, channel, slot, rank);
349
350 if (channel == 0)
351 add = count_ranks_in_channel(info, 1);
352 else
353 add = 0;
354 if (!s3resume)
355 gav(rw_test(rank + add));
356 program_timings(info, 0x00, channel, slot, rank);
357 if (!s3resume)
358 gav(rw_test(rank + add));
359 if (!s3resume)
360 gav(rw_test(rank + add));
361 write_1d0(0, 0x142, 3, 1);
362 write_1d0(0, 0x103, 6, 1);
363
364 gav(get_580(channel, 0xc | (rank << 5)));
365 gav(read_1d0(0x142, 3));
366
Felix Held04be2dd2018-07-29 04:53:22 +0200367 MCHBAR8(0x5ff) = 0x0;
368 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100369}
370
Angel Ponsc10f8b22021-01-15 20:34:51 +0100371static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100372{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100373 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
374
375 val &= 1;
376 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
377 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100378}
379
380static void set_334(int zero)
381{
382 int j, k, channel;
383 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
384 u32 vd8[2][16];
385
386 for (channel = 0; channel < NUM_CHANNELS; channel++) {
387 for (j = 0; j < 4; j++) {
388 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
389 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
390 u16 c;
391 if ((j == 0 || j == 3) && zero)
392 c = 0;
393 else if (j == 3)
394 c = 0x5f;
395 else
396 c = 0x5f5f;
397
398 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200399 MCHBAR32(0x138 + 8 * k) =
400 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100401 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200402 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100403 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200404 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100405 }
406
Felix Held22ca8cb2018-07-29 05:09:44 +0200407 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
408 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200409 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
410 zero ? 0 : (0x18191819 & lmask);
411 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
412 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
413 zero ? 0 : (a & lmask);
414 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
415 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100416 }
417 }
418
Felix Held04be2dd2018-07-29 04:53:22 +0200419 MCHBAR32_OR(0x130, 1);
420 while (MCHBAR8(0x130) & 1)
421 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100422}
423
Angel Pons244f4552021-01-15 20:41:36 +0100424static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100425{
426 u32 v;
427 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100428 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100429}
430
431static int find_highest_bit_set(u16 val)
432{
433 int i;
434 for (i = 15; i >= 0; i--)
435 if (val & (1 << i))
436 return i;
437 return -1;
438}
439
440static int find_lowest_bit_set32(u32 val)
441{
442 int i;
443 for (i = 0; i < 32; i++)
444 if (val & (1 << i))
445 return i;
446 return -1;
447}
448
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100449enum {
450 DEVICE_TYPE = 2,
451 MODULE_TYPE = 3,
452 DENSITY = 4,
453 RANKS_AND_DQ = 7,
454 MEMORY_BUS_WIDTH = 8,
455 TIMEBASE_DIVIDEND = 10,
456 TIMEBASE_DIVISOR = 11,
457 CYCLETIME = 12,
458
459 CAS_LATENCIES_LSB = 14,
460 CAS_LATENCIES_MSB = 15,
461 CAS_LATENCY_TIME = 16,
462 THERMAL_AND_REFRESH = 31,
463 REFERENCE_RAW_CARD_USED = 62,
464 RANK1_ADDRESS_MAPPING = 63
465};
466
467static void calculate_timings(struct raminfo *info)
468{
Martin Roth468d02c2019-10-23 21:44:42 -0600469 unsigned int cycletime;
470 unsigned int cas_latency_time;
471 unsigned int supported_cas_latencies;
472 unsigned int channel, slot;
473 unsigned int clock_speed_index;
474 unsigned int min_cas_latency;
475 unsigned int cas_latency;
476 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100477
478 /* Find common CAS latency */
479 supported_cas_latencies = 0x3fe;
480 for (channel = 0; channel < NUM_CHANNELS; channel++)
481 for (slot = 0; slot < NUM_SLOTS; slot++)
482 if (info->populated_ranks[channel][slot][0])
483 supported_cas_latencies &=
484 2 *
485 (info->
486 spd[channel][slot][CAS_LATENCIES_LSB] |
487 (info->
488 spd[channel][slot][CAS_LATENCIES_MSB] <<
489 8));
490
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100491 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100492
493 cycletime = min_cycletime[max_clock_index];
494 cas_latency_time = min_cas_latency_time[max_clock_index];
495
496 for (channel = 0; channel < NUM_CHANNELS; channel++)
497 for (slot = 0; slot < NUM_SLOTS; slot++)
498 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600499 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100500 timebase =
501 1000 *
502 info->
503 spd[channel][slot][TIMEBASE_DIVIDEND] /
504 info->spd[channel][slot][TIMEBASE_DIVISOR];
505 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100506 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100507 timebase *
508 info->spd[channel][slot][CYCLETIME]);
509 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100510 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100511 timebase *
512 info->
513 spd[channel][slot][CAS_LATENCY_TIME]);
514 }
Jacob Garber3c193822019-06-10 18:23:32 -0600515 if (cycletime > min_cycletime[0])
516 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100517 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
518 if (cycletime == min_cycletime[clock_speed_index])
519 break;
520 if (cycletime > min_cycletime[clock_speed_index]) {
521 clock_speed_index--;
522 cycletime = min_cycletime[clock_speed_index];
523 break;
524 }
525 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100526 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100527 cas_latency = 0;
528 while (supported_cas_latencies) {
529 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
530 if (cas_latency <= min_cas_latency)
531 break;
532 supported_cas_latencies &=
533 ~(1 << find_highest_bit_set(supported_cas_latencies));
534 }
535
536 if (cas_latency != min_cas_latency && clock_speed_index)
537 clock_speed_index--;
538
539 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
540 die("Couldn't configure DRAM");
541 info->clock_speed_index = clock_speed_index;
542 info->cas_latency = cas_latency;
543}
544
545static void program_base_timings(struct raminfo *info)
546{
Martin Roth468d02c2019-10-23 21:44:42 -0600547 unsigned int channel;
548 unsigned int slot, rank, lane;
549 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100550 int i;
551
552 extended_silicon_revision = info->silicon_revision;
553 if (info->silicon_revision == 0)
554 for (channel = 0; channel < NUM_CHANNELS; channel++)
555 for (slot = 0; slot < NUM_SLOTS; slot++)
556 if ((info->
557 spd[channel][slot][MODULE_TYPE] & 0xF) ==
558 3)
559 extended_silicon_revision = 4;
560
561 for (channel = 0; channel < NUM_CHANNELS; channel++) {
562 for (slot = 0; slot < NUM_SLOTS; slot++)
563 for (rank = 0; rank < NUM_SLOTS; rank++) {
564 int card_timing_2;
565 if (!info->populated_ranks[channel][slot][rank])
566 continue;
567
568 for (lane = 0; lane < 9; lane++) {
569 int tm_reg;
570 int card_timing;
571
572 card_timing = 0;
573 if ((info->
574 spd[channel][slot][MODULE_TYPE] &
575 0xF) == 3) {
576 int reference_card;
577 reference_card =
578 info->
579 spd[channel][slot]
580 [REFERENCE_RAW_CARD_USED] &
581 0x1f;
582 if (reference_card == 3)
583 card_timing =
584 u16_ffd1188[0][lane]
585 [info->
586 clock_speed_index];
587 if (reference_card == 5)
588 card_timing =
589 u16_ffd1188[1][lane]
590 [info->
591 clock_speed_index];
592 }
593
594 info->training.
595 lane_timings[0][channel][slot][rank]
596 [lane] =
597 u8_FFFD1218[info->
598 clock_speed_index];
599 info->training.
600 lane_timings[1][channel][slot][rank]
601 [lane] = 256;
602
603 for (tm_reg = 2; tm_reg < 4; tm_reg++)
604 info->training.
605 lane_timings[tm_reg]
606 [channel][slot][rank][lane]
607 =
608 u8_FFFD1240[channel]
609 [extended_silicon_revision]
610 [lane][2 * slot +
611 rank][info->
612 clock_speed_index]
613 + info->max4048[channel]
614 +
615 u8_FFFD0C78[channel]
616 [extended_silicon_revision]
617 [info->
618 mode4030[channel]][slot]
619 [rank][info->
620 clock_speed_index]
621 + card_timing;
622 for (tm_reg = 0; tm_reg < 4; tm_reg++)
623 write_500(info, channel,
624 info->training.
625 lane_timings[tm_reg]
626 [channel][slot][rank]
627 [lane],
628 get_timing_register_addr
629 (lane, tm_reg, slot,
630 rank), 9, 0);
631 }
632
633 card_timing_2 = 0;
634 if (!(extended_silicon_revision != 4
635 || (info->
636 populated_ranks_mask[channel] & 5) ==
637 5)) {
638 if ((info->
639 spd[channel][slot]
640 [REFERENCE_RAW_CARD_USED] & 0x1F)
641 == 3)
642 card_timing_2 =
643 u16_FFFE0EB8[0][info->
644 clock_speed_index];
645 if ((info->
646 spd[channel][slot]
647 [REFERENCE_RAW_CARD_USED] & 0x1F)
648 == 5)
649 card_timing_2 =
650 u16_FFFE0EB8[1][info->
651 clock_speed_index];
652 }
653
654 for (i = 0; i < 3; i++)
655 write_500(info, channel,
656 (card_timing_2 +
657 info->max4048[channel]
658 +
659 u8_FFFD0EF8[channel]
660 [extended_silicon_revision]
661 [info->
662 mode4030[channel]][info->
663 clock_speed_index]),
664 u16_fffd0c50[i][slot][rank],
665 8, 1);
666 write_500(info, channel,
667 (info->max4048[channel] +
668 u8_FFFD0C78[channel]
669 [extended_silicon_revision][info->
670 mode4030
671 [channel]]
672 [slot][rank][info->
673 clock_speed_index]),
674 u16_fffd0c70[slot][rank], 7, 1);
675 }
676 if (!info->populated_ranks_mask[channel])
677 continue;
678 for (i = 0; i < 3; i++)
679 write_500(info, channel,
680 (info->max4048[channel] +
681 info->avg4044[channel]
682 +
683 u8_FFFD17E0[channel]
684 [extended_silicon_revision][info->
685 mode4030
686 [channel]][info->
687 clock_speed_index]),
688 u16_fffd0c68[i], 8, 1);
689 }
690}
691
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100692/* The time of clock cycle in ps. */
693static unsigned int cycle_ps(struct raminfo *info)
694{
695 return 2 * halfcycle_ps(info);
696}
697
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100698/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600699static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100700{
701 return 100 * frequency_11(info) / 9;
702}
703
Martin Roth468d02c2019-10-23 21:44:42 -0600704static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100705{
706 return (frequency_11(info) * 2) * ps / 900000;
707}
708
Martin Roth468d02c2019-10-23 21:44:42 -0600709static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100710{
711 return (frequency_11(info)) * ns / 900;
712}
713
714static void compute_derived_timings(struct raminfo *info)
715{
Martin Roth468d02c2019-10-23 21:44:42 -0600716 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100717 int extended_silicon_revision;
718 int some_delay_1_ps;
719 int some_delay_2_ps;
720 int some_delay_2_halfcycles_ceil;
721 int some_delay_2_halfcycles_floor;
722 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100723 int some_delay_3_ps_rounded;
724 int some_delay_1_cycle_ceil;
725 int some_delay_1_cycle_floor;
726
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100727 some_delay_3_ps_rounded = 0;
728 extended_silicon_revision = info->silicon_revision;
729 if (!info->silicon_revision)
730 for (channel = 0; channel < NUM_CHANNELS; channel++)
731 for (slot = 0; slot < NUM_SLOTS; slot++)
732 if ((info->
733 spd[channel][slot][MODULE_TYPE] & 0xF) ==
734 3)
735 extended_silicon_revision = 4;
736 if (info->board_lane_delay[7] < 5)
737 info->board_lane_delay[7] = 5;
738 info->revision_flag_1 = 2;
739 if (info->silicon_revision == 2 || info->silicon_revision == 3)
740 info->revision_flag_1 = 0;
741 if (info->revision < 16)
742 info->revision_flag_1 = 0;
743
744 if (info->revision < 8)
745 info->revision_flag_1 = 0;
746 if (info->revision >= 8 && (info->silicon_revision == 0
747 || info->silicon_revision == 1))
748 some_delay_2_ps = 735;
749 else
750 some_delay_2_ps = 750;
751
752 if (info->revision >= 0x10 && (info->silicon_revision == 0
753 || info->silicon_revision == 1))
754 some_delay_1_ps = 3929;
755 else
756 some_delay_1_ps = 3490;
757
758 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
759 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
760 if (some_delay_1_ps % cycle_ps(info))
761 some_delay_1_cycle_ceil++;
762 else
763 some_delay_1_cycle_floor--;
764 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
765 if (info->revision_flag_1)
766 some_delay_2_ps = halfcycle_ps(info) >> 6;
767 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100768 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100769 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
770 375;
771 some_delay_3_ps =
772 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
773 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200774 if (some_delay_3_ps >= 150) {
775 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100776 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200777 some_delay_3_ps_rounded =
778 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
779 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100780 }
781 some_delay_2_halfcycles_ceil =
782 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
783 2 * (some_delay_1_cycle_ceil - 1);
784 if (info->revision_flag_1 && some_delay_3_ps < 150)
785 some_delay_2_halfcycles_ceil++;
786 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
787 if (info->revision < 0x10)
788 some_delay_2_halfcycles_floor =
789 some_delay_2_halfcycles_ceil - 1;
790 if (!info->revision_flag_1)
791 some_delay_2_halfcycles_floor++;
792 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
793 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
794 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
795 || (info->populated_ranks[1][0][0]
796 && info->populated_ranks[1][1][0]))
797 info->max_slots_used_in_channel = 2;
798 else
799 info->max_slots_used_in_channel = 1;
800 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200801 MCHBAR32(0x244 + (channel << 10)) =
802 ((info->revision < 8) ? 1 : 0x200) |
803 ((2 - info->max_slots_used_in_channel) << 17) |
804 (channel << 21) |
805 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100806 if (info->max_slots_used_in_channel == 1) {
807 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
808 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
809 } else {
810 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 */
811 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
812 || (count_ranks_in_channel(info, 1) ==
813 2)) ? 2 : 3;
814 }
815 for (channel = 0; channel < NUM_CHANNELS; channel++) {
816 int max_of_unk;
817 int min_of_unk_2;
818
819 int i, count;
820 int sum;
821
822 if (!info->populated_ranks_mask[channel])
823 continue;
824
825 max_of_unk = 0;
826 min_of_unk_2 = 32767;
827
828 sum = 0;
829 count = 0;
830 for (i = 0; i < 3; i++) {
831 int unk1;
832 if (info->revision < 8)
833 unk1 =
834 u8_FFFD1891[0][channel][info->
835 clock_speed_index]
836 [i];
837 else if (!
838 (info->revision >= 0x10
839 || info->revision_flag_1))
840 unk1 =
841 u8_FFFD1891[1][channel][info->
842 clock_speed_index]
843 [i];
844 else
845 unk1 = 0;
846 for (slot = 0; slot < NUM_SLOTS; slot++)
847 for (rank = 0; rank < NUM_RANKS; rank++) {
848 int a = 0;
849 int b = 0;
850
851 if (!info->
852 populated_ranks[channel][slot]
853 [rank])
854 continue;
855 if (extended_silicon_revision == 4
856 && (info->
857 populated_ranks_mask[channel] &
858 5) != 5) {
859 if ((info->
860 spd[channel][slot]
861 [REFERENCE_RAW_CARD_USED] &
862 0x1F) == 3) {
863 a = u16_ffd1178[0]
864 [info->
865 clock_speed_index];
866 b = u16_fe0eb8[0][info->
867 clock_speed_index];
868 } else
869 if ((info->
870 spd[channel][slot]
871 [REFERENCE_RAW_CARD_USED]
872 & 0x1F) == 5) {
873 a = u16_ffd1178[1]
874 [info->
875 clock_speed_index];
876 b = u16_fe0eb8[1][info->
877 clock_speed_index];
878 }
879 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100880 min_of_unk_2 = MIN(min_of_unk_2, a);
881 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100882 if (rank == 0) {
883 sum += a;
884 count++;
885 }
886 {
887 int t;
888 t = b +
889 u8_FFFD0EF8[channel]
890 [extended_silicon_revision]
891 [info->
892 mode4030[channel]][info->
893 clock_speed_index];
894 if (unk1 >= t)
895 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100896 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100897 unk1 - t);
898 }
899 }
900 {
901 int t =
902 u8_FFFD17E0[channel]
903 [extended_silicon_revision][info->
904 mode4030
905 [channel]]
906 [info->clock_speed_index] + min_of_unk_2;
907 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100908 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100909 }
910 }
911
Jacob Garber64fb4a32019-06-10 17:29:18 -0600912 if (count == 0)
913 die("No memory ranks found for channel %u\n", channel);
914
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100915 info->avg4044[channel] = sum / count;
916 info->max4048[channel] = max_of_unk;
917 }
918}
919
920static void jedec_read(struct raminfo *info,
921 int channel, int slot, int rank,
922 int total_rank, u8 addr3, unsigned int value)
923{
924 /* Handle mirrored mapping. */
925 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +0200926 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
927 ((addr3 >> 1) & 0x10);
928 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
929 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100930
931 /* Handle mirrored mapping. */
932 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
933 value =
934 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
935 << 1);
936
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800937 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100938
Felix Held04be2dd2018-07-29 04:53:22 +0200939 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
940 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100941
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800942 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100943}
944
945enum {
946 MR1_RZQ12 = 512,
947 MR1_RZQ2 = 64,
948 MR1_RZQ4 = 4,
949 MR1_ODS34OHM = 2
950};
951
952enum {
953 MR0_BT_INTERLEAVED = 8,
954 MR0_DLL_RESET_ON = 256
955};
956
957enum {
958 MR2_RTT_WR_DISABLED = 0,
959 MR2_RZQ2 = 1 << 10
960};
961
962static void jedec_init(struct raminfo *info)
963{
964 int write_recovery;
965 int channel, slot, rank;
966 int total_rank;
967 int dll_on;
968 int self_refresh_temperature;
969 int auto_self_refresh;
970
971 auto_self_refresh = 1;
972 self_refresh_temperature = 1;
973 if (info->board_lane_delay[3] <= 10) {
974 if (info->board_lane_delay[3] <= 8)
975 write_recovery = info->board_lane_delay[3] - 4;
976 else
977 write_recovery = 5;
978 } else {
979 write_recovery = 6;
980 }
981 FOR_POPULATED_RANKS {
982 auto_self_refresh &=
983 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
984 self_refresh_temperature &=
985 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
986 }
987 if (auto_self_refresh == 1)
988 self_refresh_temperature = 0;
989
990 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
991 || (info->populated_ranks[0][0][0]
992 && info->populated_ranks[0][1][0])
993 || (info->populated_ranks[1][0][0]
994 && info->populated_ranks[1][1][0]));
995
996 total_rank = 0;
997
998 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
999 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1000 int rzq_reg58e;
1001
1002 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1003 rzq_reg58e = 64;
1004 rtt = MR1_RZQ2;
1005 if (info->clock_speed_index != 0) {
1006 rzq_reg58e = 4;
1007 if (info->populated_ranks_mask[channel] == 3)
1008 rtt = MR1_RZQ4;
1009 }
1010 } else {
1011 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1012 rtt = MR1_RZQ12;
1013 rzq_reg58e = 64;
1014 rtt_wr = MR2_RZQ2;
1015 } else {
1016 rzq_reg58e = 4;
1017 rtt = MR1_RZQ4;
1018 }
1019 }
1020
Felix Held04be2dd2018-07-29 04:53:22 +02001021 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1022 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1023 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1024 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1025 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001026
1027 for (slot = 0; slot < NUM_SLOTS; slot++)
1028 for (rank = 0; rank < NUM_RANKS; rank++)
1029 if (info->populated_ranks[channel][slot][rank]) {
1030 jedec_read(info, channel, slot, rank,
1031 total_rank, 0x28,
1032 rtt_wr | (info->
1033 clock_speed_index
1034 << 3)
1035 | (auto_self_refresh << 6) |
1036 (self_refresh_temperature <<
1037 7));
1038 jedec_read(info, channel, slot, rank,
1039 total_rank, 0x38, 0);
1040 jedec_read(info, channel, slot, rank,
1041 total_rank, 0x18,
1042 rtt | MR1_ODS34OHM);
1043 jedec_read(info, channel, slot, rank,
1044 total_rank, 6,
1045 (dll_on << 12) |
1046 (write_recovery << 9)
1047 | ((info->cas_latency - 4) <<
1048 4) | MR0_BT_INTERLEAVED |
1049 MR0_DLL_RESET_ON);
1050 total_rank++;
1051 }
1052 }
1053}
1054
1055static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1056{
Martin Roth468d02c2019-10-23 21:44:42 -06001057 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001058 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1059 unsigned int channel_0_non_interleaved;
1060
1061 FOR_ALL_RANKS {
1062 if (info->populated_ranks[channel][slot][rank]) {
1063 total_mb[channel] +=
1064 pre_jedec ? 256 : (256 << info->
1065 density[channel][slot] >> info->
1066 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001067 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1068 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1069 (info->is_x16_module[channel][slot] |
1070 ((info->density[channel][slot] + 1) << 1))) |
1071 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001072 }
Felix Held04be2dd2018-07-29 04:53:22 +02001073 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1074 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001075 }
1076
1077 info->total_memory_mb = total_mb[0] + total_mb[1];
1078
1079 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001080 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001081 info->non_interleaved_part_mb =
1082 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1083 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001084 MCHBAR32(0x100) = channel_0_non_interleaved |
1085 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001086 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001087 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001088}
1089
1090static void program_board_delay(struct raminfo *info)
1091{
1092 int cas_latency_shift;
1093 int some_delay_ns;
1094 int some_delay_3_half_cycles;
1095
Martin Roth468d02c2019-10-23 21:44:42 -06001096 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001097 int high_multiplier;
1098 int lane_3_delay;
1099 int cas_latency_derived;
1100
1101 high_multiplier = 0;
1102 some_delay_ns = 200;
1103 some_delay_3_half_cycles = 4;
1104 cas_latency_shift = info->silicon_revision == 0
1105 || info->silicon_revision == 1 ? 1 : 0;
1106 if (info->revision < 8) {
1107 some_delay_ns = 600;
1108 cas_latency_shift = 0;
1109 }
1110 {
1111 int speed_bit;
1112 speed_bit =
1113 ((info->clock_speed_index > 1
1114 || (info->silicon_revision != 2
1115 && info->silicon_revision != 3))) ^ (info->revision >=
1116 0x10);
1117 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1118 3, 1);
1119 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1120 3, 1);
1121 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1122 && (info->silicon_revision == 2
1123 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001124 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001125 }
Felix Held04be2dd2018-07-29 04:53:22 +02001126 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1127 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001128
Felix Held04be2dd2018-07-29 04:53:22 +02001129 MCHBAR8(0x124) = info->board_lane_delay[4] +
1130 ((frequency_01(info) + 999) / 1000);
1131 MCHBAR16(0x125) = 0x1360;
1132 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001133 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001134 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001135 high_multiplier = 1;
1136 some_delay_2_half_cycles = ps_to_halfcycles(info,
1137 ((3 *
1138 fsbcycle_ps(info))
1139 >> 1) +
1140 (halfcycle_ps(info)
1141 *
1142 reg178_min[info->
1143 clock_speed_index]
1144 >> 6)
1145 +
1146 4 *
1147 halfcycle_ps(info)
1148 + 2230);
1149 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001150 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001151 (frequency_11(info) * 2) * (28 -
1152 some_delay_2_half_cycles) /
1153 (frequency_11(info) * 2 -
1154 4 * (info->fsb_frequency))) >> 3, 7);
1155 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001156 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001157 some_delay_3_half_cycles = 3;
1158 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001159 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1160 MCHBAR32(0x224 + (channel << 10)) =
1161 (info->max_slots_used_in_channel - 1) |
1162 ((info->cas_latency - 5 - info->clock_speed_index)
1163 << 21) | ((info->max_slots_used_in_channel +
1164 info->cas_latency - cas_latency_shift - 4) << 16) |
1165 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1166 ((info->cas_latency - info->clock_speed_index +
1167 info->max_slots_used_in_channel - 6) << 8);
1168 MCHBAR32(0x228 + (channel << 10)) =
1169 info->max_slots_used_in_channel;
1170 MCHBAR8(0x239 + (channel << 10)) = 32;
1171 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1172 (some_delay_3_half_cycles << 25) | 0x840000;
1173 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1174 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1175 MCHBAR32(0x24c + (channel << 10)) =
1176 ((!!info->clock_speed_index) << 17) |
1177 (((2 + info->clock_speed_index -
1178 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001179
Felix Held04be2dd2018-07-29 04:53:22 +02001180 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1181 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1182 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183
1184 write_500(info, channel,
1185 ((!info->populated_ranks[channel][1][1])
1186 | (!info->populated_ranks[channel][1][0] << 1)
1187 | (!info->populated_ranks[channel][0][1] << 2)
1188 | (!info->populated_ranks[channel][0][0] << 3)),
1189 0x4c9, 4, 1);
1190 }
1191
Felix Held22ca8cb2018-07-29 05:09:44 +02001192 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001193 {
1194 u8 freq_divisor = 2;
1195 if (info->fsb_frequency == frequency_11(info))
1196 freq_divisor = 3;
1197 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1198 freq_divisor = 1;
1199 else
1200 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001201 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001202 }
1203
1204 if (info->board_lane_delay[3] <= 10) {
1205 if (info->board_lane_delay[3] <= 8)
1206 lane_3_delay = info->board_lane_delay[3];
1207 else
1208 lane_3_delay = 10;
1209 } else {
1210 lane_3_delay = 12;
1211 }
1212 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1213 if (info->clock_speed_index > 1)
1214 cas_latency_derived++;
1215 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001216 MCHBAR32(0x240 + (channel << 10)) =
1217 ((info->clock_speed_index == 0) * 0x11000) |
1218 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1219 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001220 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1221 0x609, 6, 1);
1222 write_500(info, channel,
1223 info->clock_speed_index + 2 * info->cas_latency - 7,
1224 0x601, 6, 1);
1225
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR32(0x250 + (channel << 10)) =
1227 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1228 (info->board_lane_delay[7] << 2) |
1229 (info->board_lane_delay[4] << 16) |
1230 (info->board_lane_delay[1] << 25) |
1231 (info->board_lane_delay[1] << 29) | 1;
1232 MCHBAR32(0x254 + (channel << 10)) =
1233 (info->board_lane_delay[1] >> 3) |
1234 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1235 0x80 | (info->board_lane_delay[6] << 1) |
1236 (info->board_lane_delay[2] << 28) |
1237 (cas_latency_derived << 16) | 0x4700000;
1238 MCHBAR32(0x258 + (channel << 10)) =
1239 ((info->board_lane_delay[5] + info->clock_speed_index +
1240 9) << 12) | ((info->clock_speed_index -
1241 info->cas_latency + 12) << 8) |
1242 (info->board_lane_delay[2] << 17) |
1243 (info->board_lane_delay[4] << 24) | 0x47;
1244 MCHBAR32(0x25c + (channel << 10)) =
1245 (info->board_lane_delay[1] << 1) |
1246 (info->board_lane_delay[0] << 8) | 0x1da50000;
1247 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1248 MCHBAR8(0x5f8 + (channel << 10)) =
1249 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001250 }
1251
1252 program_modules_memory_map(info, 1);
1253
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001254 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001255 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1256 MCHBAR16_OR(0x612, 0x100);
1257 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001259 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001261 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001262 }
1263}
1264
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001265#define DEFAULT_PCI_MMIO_SIZE 2048
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001266
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001267static void program_total_memory_map(struct raminfo *info)
1268{
Angel Pons9333b742020-07-22 16:04:15 +02001269 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001270 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001271 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 unsigned int uma_base_igd;
1273 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001274 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001275 int memory_remap;
1276 unsigned int memory_map[8];
1277 int i;
1278 unsigned int current_limit;
1279 unsigned int tseg_base;
1280 int uma_size_igd = 0, uma_size_gtt = 0;
1281
1282 memset(memory_map, 0, sizeof(memory_map));
1283
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001284 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001285 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001286 gav(t);
1287 const int uma_sizes_gtt[16] =
1288 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1289 /* Igd memory */
1290 const int uma_sizes_igd[16] = {
1291 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1292 256, 512
1293 };
1294
1295 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1296 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1297 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001298
Angel Ponse24f97c2021-04-02 22:42:53 +02001299 mmio_size = DEFAULT_PCI_MMIO_SIZE;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001300
Angel Pons9333b742020-07-22 16:04:15 +02001301 tom = info->total_memory_mb;
1302 if (tom == 4096)
1303 tom = 4032;
1304 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1305 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1306 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001307 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001308 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001309 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001310 remap_base = MAX(4096, touud);
1311 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001312 }
Angel Pons9333b742020-07-22 16:04:15 +02001313 if (touud > 4096)
1314 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001315 quickpath_reserved = 0;
1316
Angel Pons3ab19b32020-07-22 16:29:54 +02001317 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001318
Jacob Garber975a7e32019-06-10 16:32:47 -06001319 gav(t);
1320
1321 if (t & 0x800) {
1322 u32 shift = t >> 20;
1323 if (shift == 0)
1324 die("Quickpath value is 0\n");
1325 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001326 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001327
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001328 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001329 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001330
Angel Pons9333b742020-07-22 16:04:15 +02001331 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001332 uma_base_gtt = uma_base_igd - uma_size_gtt;
1333 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1334 if (!memory_remap)
1335 tseg_base -= quickpath_reserved;
1336 tseg_base = ALIGN_DOWN(tseg_base, 8);
1337
Angel Pons16fe1e02020-07-22 16:12:33 +02001338 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1339 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001340 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001341 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1342 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001343 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001344 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001345
1346 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001347 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1348 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001349 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001350 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351
1352 current_limit = 0;
1353 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1354 memory_map[1] = 4096;
1355 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001356 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001357 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001358 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1359 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001360 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361 }
1362}
1363
1364static void collect_system_info(struct raminfo *info)
1365{
1366 u32 capid0[3];
1367 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001368 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001369
Angel Ponsb600d412021-01-16 16:33:48 +01001370 for (i = 0; i < 3; i++) {
1371 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1372 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1373 }
1374 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1375 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1376 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1377
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001378 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1379
1380 if ((capid0[1] >> 11) & 1)
1381 info->uma_enabled = 0;
1382 else
1383 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001384 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001385 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1386 info->silicon_revision = 0;
1387
1388 if (capid0[2] & 2) {
1389 info->silicon_revision = 0;
1390 info->max_supported_clock_speed_index = 2;
1391 for (channel = 0; channel < NUM_CHANNELS; channel++)
1392 if (info->populated_ranks[channel][0][0]
1393 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1394 3) {
1395 info->silicon_revision = 2;
1396 info->max_supported_clock_speed_index = 1;
1397 }
1398 } else {
1399 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1400 case 1:
1401 case 2:
1402 info->silicon_revision = 3;
1403 break;
1404 case 3:
1405 info->silicon_revision = 0;
1406 break;
1407 case 0:
1408 info->silicon_revision = 2;
1409 break;
1410 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001411 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412 case 0x40:
1413 info->silicon_revision = 0;
1414 break;
1415 case 0x48:
1416 info->silicon_revision = 1;
1417 break;
1418 }
1419 }
1420}
1421
1422static void write_training_data(struct raminfo *info)
1423{
1424 int tm, channel, slot, rank, lane;
1425 if (info->revision < 8)
1426 return;
1427
1428 for (tm = 0; tm < 4; tm++)
1429 for (channel = 0; channel < NUM_CHANNELS; channel++)
1430 for (slot = 0; slot < NUM_SLOTS; slot++)
1431 for (rank = 0; rank < NUM_RANKS; rank++)
1432 for (lane = 0; lane < 9; lane++)
1433 write_500(info, channel,
1434 info->
1435 cached_training->
1436 lane_timings[tm]
1437 [channel][slot][rank]
1438 [lane],
1439 get_timing_register_addr
1440 (lane, tm, slot,
1441 rank), 9, 0);
1442 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1443 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1444}
1445
1446static void dump_timings(struct raminfo *info)
1447{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001449 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001450 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001451 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 slot, rank);
1453 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001454 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001456 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 read_500(info, channel,
1458 get_timing_register_addr
1459 (lane, i, slot, rank),
1460 9),
1461 info->training.
1462 lane_timings[i][channel][slot][rank]
1463 [lane]);
1464 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001465 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466 }
1467 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001468 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001470 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472}
1473
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001474/* Read timings and other registers that need to be restored verbatim and
1475 put them to CBMEM.
1476 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477static void save_timings(struct raminfo *info)
1478{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001479 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480 int channel, slot, rank, lane, i;
1481
1482 train = info->training;
1483 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1484 for (i = 0; i < 4; i++)
1485 train.lane_timings[i][channel][slot][rank][lane] =
1486 read_500(info, channel,
1487 get_timing_register_addr(lane, i, slot,
1488 rank), 9);
1489 train.reg_178 = read_1d0(0x178, 7);
1490 train.reg_10b = read_1d0(0x10b, 6);
1491
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001492 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1493 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001494 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001495 train.reg274265[channel][0] = reg32 >> 16;
1496 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001497 train.reg274265[channel][2] =
1498 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001499 }
Felix Held04be2dd2018-07-29 04:53:22 +02001500 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1501 train.reg_6dc = MCHBAR32(0x6dc);
1502 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001503
Arthur Heymansb3282092019-04-14 17:53:28 +02001504 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1505 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001506
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001508 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1509 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001510}
1511
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001512static const struct ram_training *get_cached_training(void)
1513{
Shelley Chenad9cd682020-07-23 16:10:52 -07001514 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1515 MRC_CACHE_VERSION,
1516 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001517}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001518
1519/* FIXME: add timeout. */
1520static void wait_heci_ready(void)
1521{
Felix Held04be2dd2018-07-29 04:53:22 +02001522 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1523 ;
Angel Ponseb537932020-09-14 19:18:11 +02001524
1525 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001526}
1527
1528/* FIXME: add timeout. */
1529static void wait_heci_cb_avail(int len)
1530{
1531 union {
1532 struct mei_csr csr;
1533 u32 raw;
1534 } csr;
1535
Felix Held22ca8cb2018-07-29 05:09:44 +02001536 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1537 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001538
Angel Ponseb537932020-09-14 19:18:11 +02001539 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001540 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001541 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1542 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001543}
1544
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001545static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001546{
1547 int len = (head->length + 3) / 4;
1548 int i;
1549
1550 wait_heci_cb_avail(len + 1);
1551
1552 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001553 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001554 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001555 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001556
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001557 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1558 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001559}
1560
Angel Ponseb537932020-09-14 19:18:11 +02001561static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001562{
1563 struct mei_header head;
1564 int maxlen;
1565
1566 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001567 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568
1569 while (len) {
1570 int cur = len;
1571 if (cur > maxlen) {
1572 cur = maxlen;
1573 head.is_complete = 0;
1574 } else
1575 head.is_complete = 1;
1576 head.length = cur;
1577 head.reserved = 0;
1578 head.client_address = clientaddress;
1579 head.host_address = hostaddress;
1580 send_heci_packet(&head, (u32 *) msg);
1581 len -= cur;
1582 msg += cur;
1583 }
1584}
1585
1586/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001587static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588{
1589 union {
1590 struct mei_csr csr;
1591 u32 raw;
1592 } csr;
1593 int i = 0;
1594
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001595 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001596 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001597 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001598 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1599
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001600 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001602 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603 *packet_size = 0;
1604 return 0;
1605 }
Angel Ponseb537932020-09-14 19:18:11 +02001606 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607 *packet_size = 0;
1608 return -1;
1609 }
1610
Angel Ponseb537932020-09-14 19:18:11 +02001611 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001612 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001613 } while (((head->length + 3) >> 2) >
1614 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615
1616 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001617 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001618 *packet_size = head->length;
1619 if (!csr.csr.ready)
1620 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001621 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001622 return 0;
1623}
1624
Angel Ponsb1821892020-09-14 19:29:53 +02001625union uma_reply {
1626 struct {
1627 u8 group_id;
1628 u8 command;
1629 u8 reserved;
1630 u8 result;
1631 u8 field2;
1632 u8 unk3[0x48 - 4 - 1];
1633 };
1634 u32 dwords[0x48 / sizeof(u32)];
1635} __packed;
1636
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637/* FIXME: Add timeout. */
Angel Ponsb1821892020-09-14 19:29:53 +02001638static int recv_heci_message(union uma_reply *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639{
1640 struct mei_header head;
1641 int current_position;
1642
1643 current_position = 0;
1644 while (1) {
1645 u32 current_size;
1646 current_size = *message_size - current_position;
1647 if (recv_heci_packet
Angel Ponsb1821892020-09-14 19:29:53 +02001648 (&head, &message->dwords[current_position / sizeof(u32)],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649 &current_size) == -1)
1650 break;
1651 if (!current_size)
1652 break;
1653 current_position += current_size;
1654 if (head.is_complete) {
1655 *message_size = current_position;
1656 return 0;
1657 }
1658
1659 if (current_position >= *message_size)
1660 break;
1661 }
1662 *message_size = 0;
1663 return -1;
1664}
1665
Angel Pons55f11e22020-09-14 19:06:53 +02001666static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667{
Angel Ponsb1821892020-09-14 19:29:53 +02001668 union uma_reply reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001669
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670 struct uma_message {
1671 u8 group_id;
1672 u8 cmd;
1673 u8 reserved;
1674 u8 result;
1675 u32 c2;
1676 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001677 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001679 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001680 .group_id = 0,
1681 .cmd = MKHI_SET_UMA,
1682 .reserved = 0,
1683 .result = 0,
1684 .c2 = 0x82,
1685 .heci_uma_addr = heci_uma_addr,
1686 .heci_uma_size = heci_uma_size,
1687 .c3 = 0,
1688 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689 u32 reply_size;
1690
Angel Ponseb537932020-09-14 19:18:11 +02001691 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001692
1693 reply_size = sizeof(reply);
Angel Ponsb1821892020-09-14 19:29:53 +02001694 if (recv_heci_message(&reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695 return;
1696
1697 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1698 die("HECI init failed\n");
1699}
1700
1701static void setup_heci_uma(struct raminfo *info)
1702{
Angel Pons44479962021-02-24 23:08:27 +01001703 if (!info->memory_reserved_for_heci_mb || !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704 return;
1705
Angel Pons36592bf2020-09-14 18:52:44 +02001706 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001707 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001708 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 info->memory_reserved_for_heci_mb)) << 20;
1710
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001711 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001712 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001713 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001714 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001715 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001716 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001717 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001718 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001719 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001720 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001721
Angel Ponsee7fb342021-01-28 14:11:55 +01001722 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001723 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001724
Angel Ponsee7fb342021-01-28 14:11:55 +01001725 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001726 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727 }
1728
Felix Held04be2dd2018-07-29 04:53:22 +02001729 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730
Angel Pons55f11e22020-09-14 19:06:53 +02001731 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001733 pci_write_config32(HECIDEV, 0x10, 0x0);
1734 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735}
1736
1737static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1738{
1739 int ranks_in_channel;
1740 ranks_in_channel = info->populated_ranks[channel][0][0]
1741 + info->populated_ranks[channel][0][1]
1742 + info->populated_ranks[channel][1][0]
1743 + info->populated_ranks[channel][1][1];
1744
1745 /* empty channel */
1746 if (ranks_in_channel == 0)
1747 return 1;
1748
1749 if (ranks_in_channel != ranks)
1750 return 0;
1751 /* single slot */
1752 if (info->populated_ranks[channel][0][0] !=
1753 info->populated_ranks[channel][1][0])
1754 return 1;
1755 if (info->populated_ranks[channel][0][1] !=
1756 info->populated_ranks[channel][1][1])
1757 return 1;
1758 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1759 return 0;
1760 if (info->density[channel][0] != info->density[channel][1])
1761 return 0;
1762 return 1;
1763}
1764
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001765static void read_4090(struct raminfo *info)
1766{
1767 int i, channel, slot, rank, lane;
1768 for (i = 0; i < 2; i++)
1769 for (slot = 0; slot < NUM_SLOTS; slot++)
1770 for (rank = 0; rank < NUM_RANKS; rank++)
1771 for (lane = 0; lane < 9; lane++)
1772 info->training.
1773 lane_timings[0][i][slot][rank][lane]
1774 = 32;
1775
1776 for (i = 1; i < 4; i++)
1777 for (channel = 0; channel < NUM_CHANNELS; channel++)
1778 for (slot = 0; slot < NUM_SLOTS; slot++)
1779 for (rank = 0; rank < NUM_RANKS; rank++)
1780 for (lane = 0; lane < 9; lane++) {
1781 info->training.
1782 lane_timings[i][channel]
1783 [slot][rank][lane] =
1784 read_500(info, channel,
1785 get_timing_register_addr
1786 (lane, i, slot,
1787 rank), 9)
1788 + (i == 1) * 11; // !!!!
1789 }
1790
1791}
1792
1793static u32 get_etalon2(int flip, u32 addr)
1794{
1795 const u16 invmask[] = {
1796 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1797 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1798 };
1799 u32 ret;
1800 u32 comp4 = addr / 480;
1801 addr %= 480;
1802 u32 comp1 = addr & 0xf;
1803 u32 comp2 = (addr >> 4) & 1;
1804 u32 comp3 = addr >> 5;
1805
1806 if (comp4)
1807 ret = 0x1010101 << (comp4 - 1);
1808 else
1809 ret = 0;
1810 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1811 ret = ~ret;
1812
1813 return ret;
1814}
1815
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001816static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001817{
1818 msr_t msr = {.lo = 0, .hi = 0 };
1819
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001820 wrmsr(MTRR_PHYS_BASE(3), msr);
1821 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001822}
1823
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001824static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001825{
1826 msr_t msr;
1827 msr.lo = base | MTRR_TYPE_WRPROT;
1828 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001829 wrmsr(MTRR_PHYS_BASE(3), msr);
1830 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831 & 0xffffffff);
1832 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001833 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001834}
1835
1836static void flush_cache(u32 start, u32 size)
1837{
1838 u32 end;
1839 u32 addr;
1840
1841 end = start + (ALIGN_DOWN(size + 4096, 4096));
1842 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001843 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844}
1845
1846static void clear_errors(void)
1847{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001848 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849}
1850
1851static void write_testing(struct raminfo *info, int totalrank, int flip)
1852{
1853 int nwrites = 0;
1854 /* in 8-byte units. */
1855 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001856 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001857
Patrick Rudolph819c2062019-11-29 19:27:37 +01001858 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859 for (offset = 0; offset < 9 * 480; offset += 2) {
1860 write32(base + offset * 8, get_etalon2(flip, offset));
1861 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1862 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1863 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1864 nwrites += 4;
1865 if (nwrites >= 320) {
1866 clear_errors();
1867 nwrites = 0;
1868 }
1869 }
1870}
1871
1872static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1873{
1874 u8 failmask = 0;
1875 int i;
1876 int comp1, comp2, comp3;
1877 u32 failxor[2] = { 0, 0 };
1878
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001879 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001880
1881 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1882 for (comp1 = 0; comp1 < 4; comp1++)
1883 for (comp2 = 0; comp2 < 60; comp2++) {
1884 u32 re[4];
1885 u32 curroffset =
1886 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1887 read128((total_rank << 28) | (curroffset << 3),
1888 (u64 *) re);
1889 failxor[0] |=
1890 get_etalon2(flip, curroffset) ^ re[0];
1891 failxor[1] |=
1892 get_etalon2(flip, curroffset) ^ re[1];
1893 failxor[0] |=
1894 get_etalon2(flip, curroffset | 1) ^ re[2];
1895 failxor[1] |=
1896 get_etalon2(flip, curroffset | 1) ^ re[3];
1897 }
1898 for (i = 0; i < 8; i++)
1899 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1900 failmask |= 1 << i;
1901 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001902 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001903 flush_cache((total_rank << 28), 1728 * 5 * 4);
1904 return failmask;
1905}
1906
1907const u32 seed1[0x18] = {
1908 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1909 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1910 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1911 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1912 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1913 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1914};
1915
1916static u32 get_seed2(int a, int b)
1917{
1918 const u32 seed2[5] = {
1919 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1920 0x5b6db6db,
1921 };
1922 u32 r;
1923 r = seed2[(a + (a >= 10)) / 5];
1924 return b ? ~r : r;
1925}
1926
1927static int make_shift(int comp2, int comp5, int x)
1928{
1929 const u8 seed3[32] = {
1930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1931 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1932 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1933 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1934 };
1935
1936 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1937}
1938
1939static u32 get_etalon(int flip, u32 addr)
1940{
1941 u32 mask_byte = 0;
1942 int comp1 = (addr >> 1) & 1;
1943 int comp2 = (addr >> 3) & 0x1f;
1944 int comp3 = (addr >> 8) & 0xf;
1945 int comp4 = (addr >> 12) & 0xf;
1946 int comp5 = (addr >> 16) & 0x1f;
1947 u32 mask_bit = ~(0x10001 << comp3);
1948 u32 part1;
1949 u32 part2;
1950 int byte;
1951
1952 part2 =
1953 ((seed1[comp5] >>
1954 make_shift(comp2, comp5,
1955 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1956 part1 =
1957 ((seed1[comp5] >>
1958 make_shift(comp2, comp5,
1959 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1960
1961 for (byte = 0; byte < 4; byte++)
1962 if ((get_seed2(comp5, comp4) >>
1963 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1964 mask_byte |= 0xff << (8 * byte);
1965
1966 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1967 (comp3 + 16));
1968}
1969
1970static void
1971write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1972 char flip)
1973{
1974 int i;
1975 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001976 write32p((totalrank << 28) | (region << 25) | (block << 16) |
1977 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001978}
1979
1980static u8
1981check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1982 char flip)
1983{
1984 u8 failmask = 0;
1985 u32 failxor[2];
1986 int i;
1987 int comp1, comp2, comp3;
1988
1989 failxor[0] = 0;
1990 failxor[1] = 0;
1991
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001992 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001993 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
1994 for (comp1 = 0; comp1 < 16; comp1++)
1995 for (comp2 = 0; comp2 < 64; comp2++) {
1996 u32 addr =
1997 (totalrank << 28) | (region << 25) | (block
1998 << 16)
1999 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2000 2);
2001 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002002 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002003 }
2004 for (i = 0; i < 8; i++)
2005 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2006 failmask |= 1 << i;
2007 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002008 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002009 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2010 return failmask;
2011}
2012
2013static int check_bounded(unsigned short *vals, u16 bound)
2014{
2015 int i;
2016
2017 for (i = 0; i < 8; i++)
2018 if (vals[i] < bound)
2019 return 0;
2020 return 1;
2021}
2022
2023enum state {
2024 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2025};
2026
2027static int validate_state(enum state *in)
2028{
2029 int i;
2030 for (i = 0; i < 8; i++)
2031 if (in[i] != COMPLETE)
2032 return 0;
2033 return 1;
2034}
2035
2036static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002037do_fsm(enum state *state, u16 *counter,
2038 u8 fail_mask, int margin, int uplimit,
2039 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002040{
2041 int lane;
2042
2043 for (lane = 0; lane < 8; lane++) {
2044 int is_fail = (fail_mask >> lane) & 1;
2045 switch (state[lane]) {
2046 case BEFORE_USABLE:
2047 if (!is_fail) {
2048 counter[lane] = 1;
2049 state[lane] = AT_USABLE;
2050 break;
2051 }
2052 counter[lane] = 0;
2053 state[lane] = BEFORE_USABLE;
2054 break;
2055 case AT_USABLE:
2056 if (!is_fail) {
2057 ++counter[lane];
2058 if (counter[lane] >= margin) {
2059 state[lane] = AT_MARGIN;
2060 res_low[lane] = val - margin + 1;
2061 break;
2062 }
2063 state[lane] = 1;
2064 break;
2065 }
2066 counter[lane] = 0;
2067 state[lane] = BEFORE_USABLE;
2068 break;
2069 case AT_MARGIN:
2070 if (is_fail) {
2071 state[lane] = COMPLETE;
2072 res_high[lane] = val - 1;
2073 } else {
2074 counter[lane]++;
2075 state[lane] = AT_MARGIN;
2076 if (val == uplimit) {
2077 state[lane] = COMPLETE;
2078 res_high[lane] = uplimit;
2079 }
2080 }
2081 break;
2082 case COMPLETE:
2083 break;
2084 }
2085 }
2086}
2087
2088static void
2089train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2090 u8 total_rank, u8 reg_178, int first_run, int niter,
2091 timing_bounds_t * timings)
2092{
2093 int lane;
2094 enum state state[8];
2095 u16 count[8];
2096 u8 lower_usable[8];
2097 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002098 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002099 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002100 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002101
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002102 for (i = 0; i < 8; i++)
2103 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002104
2105 if (!first_run) {
2106 int is_all_ok = 1;
2107 for (lane = 0; lane < 8; lane++)
2108 if (timings[reg_178][channel][slot][rank][lane].
2109 smallest ==
2110 timings[reg_178][channel][slot][rank][lane].
2111 largest) {
2112 timings[reg_178][channel][slot][rank][lane].
2113 smallest = 0;
2114 timings[reg_178][channel][slot][rank][lane].
2115 largest = 0;
2116 is_all_ok = 0;
2117 }
2118 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002119 for (i = 0; i < 8; i++)
2120 state[i] = COMPLETE;
2121 }
2122 }
2123
2124 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2125 u8 failmask = 0;
2126 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2127 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2128 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002129 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002130 do_fsm(state, count, failmask, 5, 47, lower_usable,
2131 upper_usable, reg1b3);
2132 }
2133
2134 if (reg1b3) {
2135 write_1d0(0, 0x1b3, 6, 1);
2136 write_1d0(0, 0x1a3, 6, 1);
2137 for (lane = 0; lane < 8; lane++) {
2138 if (state[lane] == COMPLETE) {
2139 timings[reg_178][channel][slot][rank][lane].
2140 smallest =
2141 lower_usable[lane] +
2142 (info->training.
2143 lane_timings[0][channel][slot][rank][lane]
2144 & 0x3F) - 32;
2145 timings[reg_178][channel][slot][rank][lane].
2146 largest =
2147 upper_usable[lane] +
2148 (info->training.
2149 lane_timings[0][channel][slot][rank][lane]
2150 & 0x3F) - 32;
2151 }
2152 }
2153 }
2154
2155 if (!first_run) {
2156 for (lane = 0; lane < 8; lane++)
2157 if (state[lane] == COMPLETE) {
2158 write_500(info, channel,
2159 timings[reg_178][channel][slot][rank]
2160 [lane].smallest,
2161 get_timing_register_addr(lane, 0,
2162 slot, rank),
2163 9, 1);
2164 write_500(info, channel,
2165 timings[reg_178][channel][slot][rank]
2166 [lane].smallest +
2167 info->training.
2168 lane_timings[1][channel][slot][rank]
2169 [lane]
2170 -
2171 info->training.
2172 lane_timings[0][channel][slot][rank]
2173 [lane], get_timing_register_addr(lane,
2174 1,
2175 slot,
2176 rank),
2177 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002178 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002179 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002180 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002181
2182 do {
2183 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002184 for (i = 0; i < niter; i++) {
2185 if (failmask == 0xFF)
2186 break;
2187 failmask |=
2188 check_testing_type2(info, total_rank, 2, i,
2189 0);
2190 failmask |=
2191 check_testing_type2(info, total_rank, 3, i,
2192 1);
2193 }
Felix Held04be2dd2018-07-29 04:53:22 +02002194 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002195 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002196 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002197 if ((1 << lane) & failmask) {
2198 if (timings[reg_178][channel]
2199 [slot][rank][lane].
2200 largest <=
2201 timings[reg_178][channel]
2202 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002203 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002204 [lane] = -1;
2205 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002206 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002207 [lane] = 0;
2208 timings[reg_178]
2209 [channel][slot]
2210 [rank][lane].
2211 smallest++;
2212 write_500(info, channel,
2213 timings
2214 [reg_178]
2215 [channel]
2216 [slot][rank]
2217 [lane].
2218 smallest,
2219 get_timing_register_addr
2220 (lane, 0,
2221 slot, rank),
2222 9, 1);
2223 write_500(info, channel,
2224 timings
2225 [reg_178]
2226 [channel]
2227 [slot][rank]
2228 [lane].
2229 smallest +
2230 info->
2231 training.
2232 lane_timings
2233 [1][channel]
2234 [slot][rank]
2235 [lane]
2236 -
2237 info->
2238 training.
2239 lane_timings
2240 [0][channel]
2241 [slot][rank]
2242 [lane],
2243 get_timing_register_addr
2244 (lane, 1,
2245 slot, rank),
2246 9, 1);
2247 }
2248 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002249 num_successfully_checked[lane]
2250 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002251 }
2252 }
Felix Held04be2dd2018-07-29 04:53:22 +02002253 while (!check_bounded(num_successfully_checked, 2))
2254 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002255
2256 for (lane = 0; lane < 8; lane++)
2257 if (state[lane] == COMPLETE) {
2258 write_500(info, channel,
2259 timings[reg_178][channel][slot][rank]
2260 [lane].largest,
2261 get_timing_register_addr(lane, 0,
2262 slot, rank),
2263 9, 1);
2264 write_500(info, channel,
2265 timings[reg_178][channel][slot][rank]
2266 [lane].largest +
2267 info->training.
2268 lane_timings[1][channel][slot][rank]
2269 [lane]
2270 -
2271 info->training.
2272 lane_timings[0][channel][slot][rank]
2273 [lane], get_timing_register_addr(lane,
2274 1,
2275 slot,
2276 rank),
2277 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002278 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002279 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002280 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002281
2282 do {
2283 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002284 for (i = 0; i < niter; i++) {
2285 if (failmask == 0xFF)
2286 break;
2287 failmask |=
2288 check_testing_type2(info, total_rank, 2, i,
2289 0);
2290 failmask |=
2291 check_testing_type2(info, total_rank, 3, i,
2292 1);
2293 }
2294
Felix Held04be2dd2018-07-29 04:53:22 +02002295 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002296 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002297 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002298 if ((1 << lane) & failmask) {
2299 if (timings[reg_178][channel]
2300 [slot][rank][lane].
2301 largest <=
2302 timings[reg_178][channel]
2303 [slot][rank][lane].
2304 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002305 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 [lane] = -1;
2307 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002308 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002309 [lane] = 0;
2310 timings[reg_178]
2311 [channel][slot]
2312 [rank][lane].
2313 largest--;
2314 write_500(info, channel,
2315 timings
2316 [reg_178]
2317 [channel]
2318 [slot][rank]
2319 [lane].
2320 largest,
2321 get_timing_register_addr
2322 (lane, 0,
2323 slot, rank),
2324 9, 1);
2325 write_500(info, channel,
2326 timings
2327 [reg_178]
2328 [channel]
2329 [slot][rank]
2330 [lane].
2331 largest +
2332 info->
2333 training.
2334 lane_timings
2335 [1][channel]
2336 [slot][rank]
2337 [lane]
2338 -
2339 info->
2340 training.
2341 lane_timings
2342 [0][channel]
2343 [slot][rank]
2344 [lane],
2345 get_timing_register_addr
2346 (lane, 1,
2347 slot, rank),
2348 9, 1);
2349 }
2350 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002351 num_successfully_checked[lane]
2352 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002353 }
2354 }
2355 }
Felix Held04be2dd2018-07-29 04:53:22 +02002356 while (!check_bounded(num_successfully_checked, 3))
2357 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002358
2359 for (lane = 0; lane < 8; lane++) {
2360 write_500(info, channel,
2361 info->training.
2362 lane_timings[0][channel][slot][rank][lane],
2363 get_timing_register_addr(lane, 0, slot, rank),
2364 9, 1);
2365 write_500(info, channel,
2366 info->training.
2367 lane_timings[1][channel][slot][rank][lane],
2368 get_timing_register_addr(lane, 1, slot, rank),
2369 9, 1);
2370 if (timings[reg_178][channel][slot][rank][lane].
2371 largest <=
2372 timings[reg_178][channel][slot][rank][lane].
2373 smallest) {
2374 timings[reg_178][channel][slot][rank][lane].
2375 largest = 0;
2376 timings[reg_178][channel][slot][rank][lane].
2377 smallest = 0;
2378 }
2379 }
2380 }
2381}
2382
2383static void set_10b(struct raminfo *info, u8 val)
2384{
2385 int channel;
2386 int slot, rank;
2387 int lane;
2388
2389 if (read_1d0(0x10b, 6) == val)
2390 return;
2391
2392 write_1d0(val, 0x10b, 6, 1);
2393
2394 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2395 u16 reg_500;
2396 reg_500 = read_500(info, channel,
2397 get_timing_register_addr(lane, 0, slot,
2398 rank), 9);
2399 if (val == 1) {
2400 if (lut16[info->clock_speed_index] <= reg_500)
2401 reg_500 -= lut16[info->clock_speed_index];
2402 else
2403 reg_500 = 0;
2404 } else {
2405 reg_500 += lut16[info->clock_speed_index];
2406 }
2407 write_500(info, channel, reg_500,
2408 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2409 }
2410}
2411
2412static void set_ecc(int onoff)
2413{
2414 int channel;
2415 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2416 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002417 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002418 if (onoff)
2419 t |= 1;
2420 else
2421 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002422 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423 }
2424}
2425
2426static void set_178(u8 val)
2427{
2428 if (val >= 31)
2429 val = val - 31;
2430 else
2431 val = 63 - val;
2432
2433 write_1d0(2 * val, 0x178, 7, 1);
2434}
2435
2436static void
2437write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2438 int type)
2439{
2440 int lane;
2441
2442 for (lane = 0; lane < 8; lane++)
2443 write_500(info, channel,
2444 info->training.
2445 lane_timings[type][channel][slot][rank][lane],
2446 get_timing_register_addr(lane, type, slot, rank), 9,
2447 0);
2448}
2449
2450static void
2451try_timing_offsets(struct raminfo *info, int channel,
2452 int slot, int rank, int totalrank)
2453{
2454 u16 count[8];
2455 enum state state[8];
2456 u8 lower_usable[8], upper_usable[8];
2457 int lane;
2458 int i;
2459 int flip = 1;
2460 int timing_offset;
2461
2462 for (i = 0; i < 8; i++)
2463 state[i] = BEFORE_USABLE;
2464
2465 memset(count, 0, sizeof(count));
2466
2467 for (lane = 0; lane < 8; lane++)
2468 write_500(info, channel,
2469 info->training.
2470 lane_timings[2][channel][slot][rank][lane] + 32,
2471 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2472
2473 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2474 timing_offset++) {
2475 u8 failmask;
2476 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2477 failmask = 0;
2478 for (i = 0; i < 2 && failmask != 0xff; i++) {
2479 flip = !flip;
2480 write_testing(info, totalrank, flip);
2481 failmask |= check_testing(info, totalrank, flip);
2482 }
2483 do_fsm(state, count, failmask, 10, 63, lower_usable,
2484 upper_usable, timing_offset);
2485 }
2486 write_1d0(0, 0x1bb, 6, 1);
2487 dump_timings(info);
2488 if (!validate_state(state))
2489 die("Couldn't discover DRAM timings (1)\n");
2490
2491 for (lane = 0; lane < 8; lane++) {
2492 u8 bias = 0;
2493
2494 if (info->silicon_revision) {
2495 int usable_length;
2496
2497 usable_length = upper_usable[lane] - lower_usable[lane];
2498 if (usable_length >= 20) {
2499 bias = usable_length / 2 - 10;
2500 if (bias >= 2)
2501 bias = 2;
2502 }
2503 }
2504 write_500(info, channel,
2505 info->training.
2506 lane_timings[2][channel][slot][rank][lane] +
2507 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2508 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2509 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2510 info->training.lane_timings[2][channel][slot][rank][lane] +
2511 lower_usable[lane];
2512 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2513 info->training.lane_timings[2][channel][slot][rank][lane] +
2514 upper_usable[lane];
2515 info->training.timing2_offset[channel][slot][rank][lane] =
2516 info->training.lane_timings[2][channel][slot][rank][lane];
2517 }
2518}
2519
2520static u8
2521choose_training(struct raminfo *info, int channel, int slot, int rank,
2522 int lane, timing_bounds_t * timings, u8 center_178)
2523{
2524 u16 central_weight;
2525 u16 side_weight;
2526 unsigned int sum = 0, count = 0;
2527 u8 span;
2528 u8 lower_margin, upper_margin;
2529 u8 reg_178;
2530 u8 result;
2531
2532 span = 12;
2533 central_weight = 20;
2534 side_weight = 20;
2535 if (info->silicon_revision == 1 && channel == 1) {
2536 central_weight = 5;
2537 side_weight = 20;
2538 if ((info->
2539 populated_ranks_mask[1] ^ (info->
2540 populated_ranks_mask[1] >> 2)) &
2541 1)
2542 span = 18;
2543 }
2544 if ((info->populated_ranks_mask[0] & 5) == 5) {
2545 central_weight = 20;
2546 side_weight = 20;
2547 }
2548 if (info->clock_speed_index >= 2
2549 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2550 if (info->silicon_revision == 1) {
2551 switch (channel) {
2552 case 0:
2553 if (lane == 1) {
2554 central_weight = 10;
2555 side_weight = 20;
2556 }
2557 break;
2558 case 1:
2559 if (lane == 6) {
2560 side_weight = 5;
2561 central_weight = 20;
2562 }
2563 break;
2564 }
2565 }
2566 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2567 side_weight = 5;
2568 central_weight = 20;
2569 }
2570 }
2571 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2572 reg_178 += span) {
2573 u8 smallest;
2574 u8 largest;
2575 largest = timings[reg_178][channel][slot][rank][lane].largest;
2576 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2577 if (largest - smallest + 1 >= 5) {
2578 unsigned int weight;
2579 if (reg_178 == center_178)
2580 weight = central_weight;
2581 else
2582 weight = side_weight;
2583 sum += weight * (largest + smallest);
2584 count += weight;
2585 }
2586 }
2587 dump_timings(info);
2588 if (count == 0)
2589 die("Couldn't discover DRAM timings (2)\n");
2590 result = sum / (2 * count);
2591 lower_margin =
2592 result - timings[center_178][channel][slot][rank][lane].smallest;
2593 upper_margin =
2594 timings[center_178][channel][slot][rank][lane].largest - result;
2595 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002596 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002597 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002598 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002599 return result;
2600}
2601
2602#define STANDARD_MIN_MARGIN 5
2603
2604static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2605{
2606 u16 margin[64];
2607 int lane, rank, slot, channel;
2608 u8 reg178;
2609 int count = 0, sum = 0;
2610
2611 for (reg178 = reg178_min[info->clock_speed_index];
2612 reg178 < reg178_max[info->clock_speed_index];
2613 reg178 += reg178_step[info->clock_speed_index]) {
2614 margin[reg178] = -1;
2615 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2616 int curmargin =
2617 timings[reg178][channel][slot][rank][lane].largest -
2618 timings[reg178][channel][slot][rank][lane].
2619 smallest + 1;
2620 if (curmargin < margin[reg178])
2621 margin[reg178] = curmargin;
2622 }
2623 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2624 u16 weight;
2625 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2626 sum += weight * reg178;
2627 count += weight;
2628 }
2629 }
2630 dump_timings(info);
2631 if (count == 0)
2632 die("Couldn't discover DRAM timings (3)\n");
2633
2634 u8 threshold;
2635
2636 for (threshold = 30; threshold >= 5; threshold--) {
2637 int usable_length = 0;
2638 int smallest_fount = 0;
2639 for (reg178 = reg178_min[info->clock_speed_index];
2640 reg178 < reg178_max[info->clock_speed_index];
2641 reg178 += reg178_step[info->clock_speed_index])
2642 if (margin[reg178] >= threshold) {
2643 usable_length +=
2644 reg178_step[info->clock_speed_index];
2645 info->training.reg178_largest =
2646 reg178 -
2647 2 * reg178_step[info->clock_speed_index];
2648
2649 if (!smallest_fount) {
2650 smallest_fount = 1;
2651 info->training.reg178_smallest =
2652 reg178 +
2653 reg178_step[info->
2654 clock_speed_index];
2655 }
2656 }
2657 if (usable_length >= 0x21)
2658 break;
2659 }
2660
2661 return sum / count;
2662}
2663
2664static int check_cached_sanity(struct raminfo *info)
2665{
2666 int lane;
2667 int slot, rank;
2668 int channel;
2669
2670 if (!info->cached_training)
2671 return 0;
2672
2673 for (channel = 0; channel < NUM_CHANNELS; channel++)
2674 for (slot = 0; slot < NUM_SLOTS; slot++)
2675 for (rank = 0; rank < NUM_RANKS; rank++)
2676 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2677 u16 cached_value, estimation_value;
2678 cached_value =
2679 info->cached_training->
2680 lane_timings[1][channel][slot][rank]
2681 [lane];
2682 if (cached_value >= 0x18
2683 && cached_value <= 0x1E7) {
2684 estimation_value =
2685 info->training.
2686 lane_timings[1][channel]
2687 [slot][rank][lane];
2688 if (estimation_value <
2689 cached_value - 24)
2690 return 0;
2691 if (estimation_value >
2692 cached_value + 24)
2693 return 0;
2694 }
2695 }
2696 return 1;
2697}
2698
2699static int try_cached_training(struct raminfo *info)
2700{
2701 u8 saved_243[2];
2702 u8 tm;
2703
2704 int channel, slot, rank, lane;
2705 int flip = 1;
2706 int i, j;
2707
2708 if (!check_cached_sanity(info))
2709 return 0;
2710
2711 info->training.reg178_center = info->cached_training->reg178_center;
2712 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2713 info->training.reg178_largest = info->cached_training->reg178_largest;
2714 memcpy(&info->training.timing_bounds,
2715 &info->cached_training->timing_bounds,
2716 sizeof(info->training.timing_bounds));
2717 memcpy(&info->training.timing_offset,
2718 &info->cached_training->timing_offset,
2719 sizeof(info->training.timing_offset));
2720
2721 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002722 saved_243[0] = MCHBAR8(0x243);
2723 saved_243[1] = MCHBAR8(0x643);
2724 MCHBAR8(0x243) = saved_243[0] | 2;
2725 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002726 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002727 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002728 if (read_1d0(0x10b, 6) & 1)
2729 set_10b(info, 0);
2730 for (tm = 0; tm < 2; tm++) {
2731 int totalrank;
2732
2733 set_178(tm ? info->cached_training->reg178_largest : info->
2734 cached_training->reg178_smallest);
2735
2736 totalrank = 0;
2737 /* Check timing ranges. With i == 0 we check smallest one and with
2738 i == 1 the largest bound. With j == 0 we check that on the bound
2739 it still works whereas with j == 1 we check that just outside of
2740 bound we fail.
2741 */
2742 FOR_POPULATED_RANKS_BACKWARDS {
2743 for (i = 0; i < 2; i++) {
2744 for (lane = 0; lane < 8; lane++) {
2745 write_500(info, channel,
2746 info->cached_training->
2747 timing2_bounds[channel][slot]
2748 [rank][lane][i],
2749 get_timing_register_addr(lane,
2750 3,
2751 slot,
2752 rank),
2753 9, 1);
2754
2755 if (!i)
2756 write_500(info, channel,
2757 info->
2758 cached_training->
2759 timing2_offset
2760 [channel][slot][rank]
2761 [lane],
2762 get_timing_register_addr
2763 (lane, 2, slot, rank),
2764 9, 1);
2765 write_500(info, channel,
2766 i ? info->cached_training->
2767 timing_bounds[tm][channel]
2768 [slot][rank][lane].
2769 largest : info->
2770 cached_training->
2771 timing_bounds[tm][channel]
2772 [slot][rank][lane].smallest,
2773 get_timing_register_addr(lane,
2774 0,
2775 slot,
2776 rank),
2777 9, 1);
2778 write_500(info, channel,
2779 info->cached_training->
2780 timing_offset[channel][slot]
2781 [rank][lane] +
2782 (i ? info->cached_training->
2783 timing_bounds[tm][channel]
2784 [slot][rank][lane].
2785 largest : info->
2786 cached_training->
2787 timing_bounds[tm][channel]
2788 [slot][rank][lane].
2789 smallest) - 64,
2790 get_timing_register_addr(lane,
2791 1,
2792 slot,
2793 rank),
2794 9, 1);
2795 }
2796 for (j = 0; j < 2; j++) {
2797 u8 failmask;
2798 u8 expected_failmask;
2799 char reg1b3;
2800
2801 reg1b3 = (j == 1) + 4;
2802 reg1b3 =
2803 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2804 write_1d0(reg1b3, 0x1bb, 6, 1);
2805 write_1d0(reg1b3, 0x1b3, 6, 1);
2806 write_1d0(reg1b3, 0x1a3, 6, 1);
2807
2808 flip = !flip;
2809 write_testing(info, totalrank, flip);
2810 failmask =
2811 check_testing(info, totalrank,
2812 flip);
2813 expected_failmask =
2814 j == 0 ? 0x00 : 0xff;
2815 if (failmask != expected_failmask)
2816 goto fail;
2817 }
2818 }
2819 totalrank++;
2820 }
2821 }
2822
2823 set_178(info->cached_training->reg178_center);
2824 if (info->use_ecc)
2825 set_ecc(1);
2826 write_training_data(info);
2827 write_1d0(0, 322, 3, 1);
2828 info->training = *info->cached_training;
2829
2830 write_1d0(0, 0x1bb, 6, 1);
2831 write_1d0(0, 0x1b3, 6, 1);
2832 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002833 MCHBAR8(0x243) = saved_243[0];
2834 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002835
2836 return 1;
2837
2838fail:
2839 FOR_POPULATED_RANKS {
2840 write_500_timings_type(info, channel, slot, rank, 1);
2841 write_500_timings_type(info, channel, slot, rank, 2);
2842 write_500_timings_type(info, channel, slot, rank, 3);
2843 }
2844
2845 write_1d0(0, 0x1bb, 6, 1);
2846 write_1d0(0, 0x1b3, 6, 1);
2847 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002848 MCHBAR8(0x243) = saved_243[0];
2849 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002850
2851 return 0;
2852}
2853
2854static void do_ram_training(struct raminfo *info)
2855{
2856 u8 saved_243[2];
2857 int totalrank = 0;
2858 u8 reg_178;
2859 int niter;
2860
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002861 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002862 int lane, rank, slot, channel;
2863 u8 reg178_center;
2864
2865 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002866 saved_243[0] = MCHBAR8(0x243);
2867 saved_243[1] = MCHBAR8(0x643);
2868 MCHBAR8(0x243) = saved_243[0] | 2;
2869 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002870 switch (info->clock_speed_index) {
2871 case 0:
2872 niter = 5;
2873 break;
2874 case 1:
2875 niter = 10;
2876 break;
2877 default:
2878 niter = 19;
2879 break;
2880 }
2881 set_ecc(0);
2882
2883 FOR_POPULATED_RANKS_BACKWARDS {
2884 int i;
2885
2886 write_500_timings_type(info, channel, slot, rank, 0);
2887
2888 write_testing(info, totalrank, 0);
2889 for (i = 0; i < niter; i++) {
2890 write_testing_type2(info, totalrank, 2, i, 0);
2891 write_testing_type2(info, totalrank, 3, i, 1);
2892 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002893 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002894 totalrank++;
2895 }
2896
2897 if (reg178_min[info->clock_speed_index] <
2898 reg178_max[info->clock_speed_index])
2899 memset(timings[reg178_min[info->clock_speed_index]], 0,
2900 sizeof(timings[0]) *
2901 (reg178_max[info->clock_speed_index] -
2902 reg178_min[info->clock_speed_index]));
2903 for (reg_178 = reg178_min[info->clock_speed_index];
2904 reg_178 < reg178_max[info->clock_speed_index];
2905 reg_178 += reg178_step[info->clock_speed_index]) {
2906 totalrank = 0;
2907 set_178(reg_178);
2908 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2909 for (slot = 0; slot < NUM_SLOTS; slot++)
2910 for (rank = 0; rank < NUM_RANKS; rank++) {
2911 memset(&timings[reg_178][channel][slot]
2912 [rank][0].smallest, 0, 16);
2913 if (info->
2914 populated_ranks[channel][slot]
2915 [rank]) {
2916 train_ram_at_178(info, channel,
2917 slot, rank,
2918 totalrank,
2919 reg_178, 1,
2920 niter,
2921 timings);
2922 totalrank++;
2923 }
2924 }
2925 }
2926
2927 reg178_center = choose_reg178(info, timings);
2928
2929 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2930 info->training.timing_bounds[0][channel][slot][rank][lane].
2931 smallest =
2932 timings[info->training.
2933 reg178_smallest][channel][slot][rank][lane].
2934 smallest;
2935 info->training.timing_bounds[0][channel][slot][rank][lane].
2936 largest =
2937 timings[info->training.
2938 reg178_smallest][channel][slot][rank][lane].largest;
2939 info->training.timing_bounds[1][channel][slot][rank][lane].
2940 smallest =
2941 timings[info->training.
2942 reg178_largest][channel][slot][rank][lane].smallest;
2943 info->training.timing_bounds[1][channel][slot][rank][lane].
2944 largest =
2945 timings[info->training.
2946 reg178_largest][channel][slot][rank][lane].largest;
2947 info->training.timing_offset[channel][slot][rank][lane] =
2948 info->training.lane_timings[1][channel][slot][rank][lane]
2949 -
2950 info->training.lane_timings[0][channel][slot][rank][lane] +
2951 64;
2952 }
2953
2954 if (info->silicon_revision == 1
2955 && (info->
2956 populated_ranks_mask[1] ^ (info->
2957 populated_ranks_mask[1] >> 2)) & 1) {
2958 int ranks_after_channel1;
2959
2960 totalrank = 0;
2961 for (reg_178 = reg178_center - 18;
2962 reg_178 <= reg178_center + 18; reg_178 += 18) {
2963 totalrank = 0;
2964 set_178(reg_178);
2965 for (slot = 0; slot < NUM_SLOTS; slot++)
2966 for (rank = 0; rank < NUM_RANKS; rank++) {
2967 if (info->
2968 populated_ranks[1][slot][rank]) {
2969 train_ram_at_178(info, 1, slot,
2970 rank,
2971 totalrank,
2972 reg_178, 0,
2973 niter,
2974 timings);
2975 totalrank++;
2976 }
2977 }
2978 }
2979 ranks_after_channel1 = totalrank;
2980
2981 for (reg_178 = reg178_center - 12;
2982 reg_178 <= reg178_center + 12; reg_178 += 12) {
2983 totalrank = ranks_after_channel1;
2984 set_178(reg_178);
2985 for (slot = 0; slot < NUM_SLOTS; slot++)
2986 for (rank = 0; rank < NUM_RANKS; rank++)
2987 if (info->
2988 populated_ranks[0][slot][rank]) {
2989 train_ram_at_178(info, 0, slot,
2990 rank,
2991 totalrank,
2992 reg_178, 0,
2993 niter,
2994 timings);
2995 totalrank++;
2996 }
2997
2998 }
2999 } else {
3000 for (reg_178 = reg178_center - 12;
3001 reg_178 <= reg178_center + 12; reg_178 += 12) {
3002 totalrank = 0;
3003 set_178(reg_178);
3004 FOR_POPULATED_RANKS_BACKWARDS {
3005 train_ram_at_178(info, channel, slot, rank,
3006 totalrank, reg_178, 0, niter,
3007 timings);
3008 totalrank++;
3009 }
3010 }
3011 }
3012
3013 set_178(reg178_center);
3014 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3015 u16 tm0;
3016
3017 tm0 =
3018 choose_training(info, channel, slot, rank, lane, timings,
3019 reg178_center);
3020 write_500(info, channel, tm0,
3021 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3022 write_500(info, channel,
3023 tm0 +
3024 info->training.
3025 lane_timings[1][channel][slot][rank][lane] -
3026 info->training.
3027 lane_timings[0][channel][slot][rank][lane],
3028 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3029 }
3030
3031 totalrank = 0;
3032 FOR_POPULATED_RANKS_BACKWARDS {
3033 try_timing_offsets(info, channel, slot, rank, totalrank);
3034 totalrank++;
3035 }
Felix Held04be2dd2018-07-29 04:53:22 +02003036 MCHBAR8(0x243) = saved_243[0];
3037 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003038 write_1d0(0, 0x142, 3, 1);
3039 info->training.reg178_center = reg178_center;
3040}
3041
3042static void ram_training(struct raminfo *info)
3043{
3044 u16 saved_fc4;
3045
Felix Held04be2dd2018-07-29 04:53:22 +02003046 saved_fc4 = MCHBAR16(0xfc4);
3047 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003048
3049 if (info->revision >= 8)
3050 read_4090(info);
3051
3052 if (!try_cached_training(info))
3053 do_ram_training(info);
3054 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3055 && info->clock_speed_index < 2)
3056 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003057 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003058}
3059
Angel Pons7a87c922021-01-15 22:50:41 +01003060u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003061{
3062 int slot, rank, lane;
3063 u16 ret = 0;
3064
Felix Held04be2dd2018-07-29 04:53:22 +02003065 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003066 return 384;
3067
3068 if (info->revision < 8)
3069 return 256;
3070
3071 for (slot = 0; slot < NUM_SLOTS; slot++)
3072 for (rank = 0; rank < NUM_RANKS; rank++)
3073 if (info->populated_ranks[channel][slot][rank])
3074 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003075 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003076 get_timing_register_addr
3077 (lane, 0, slot,
3078 rank), 9));
3079 return ret;
3080}
3081
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003082static void dmi_setup(void)
3083{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003084 gav(DMIBAR8(0x254));
3085 DMIBAR8(0x254) = 0x1;
3086 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003087 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003088
Angel Ponsd071c4d2020-09-14 23:51:35 +02003089 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003090
3091 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3092 DEFAULT_GPIOBASE | 0x38);
3093 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3094}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003095
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003096void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003097{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003098 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003099 u16 ggc;
3100 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003101
Felix Held04be2dd2018-07-29 04:53:22 +02003102 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003103 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3104 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003105 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003106 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003107 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003108
3109 dmi_setup();
3110
Felix Held04be2dd2018-07-29 04:53:22 +02003111 MCHBAR16(0x1170) = 0xa880;
3112 MCHBAR8(0x11c1) = 0x1;
3113 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003114 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003115
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003116 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3117 /* 0 for 32MB */
3118 gfxsize = 0;
3119 }
3120
3121 ggc = 0xb00 | ((gfxsize + 5) << 4);
3122
Angel Pons16fe1e02020-07-22 16:12:33 +02003123 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003124
3125 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003126 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003127
3128 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003129 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003130 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003131 MCHBAR16_OR(0x2c30, 0x200);
3132 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003133 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003134 pci_read_config8(GMA, MSAC); // = 0x2
3135 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003136 RCBA8(0x2318);
3137 RCBA8(0x2318) = 0x47;
3138 RCBA8(0x2320);
3139 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003140 }
3141
Felix Heldf83d80b2018-07-29 05:30:30 +02003142 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003143
Angel Pons16fe1e02020-07-22 16:12:33 +02003144 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003145 gav(RCBA32(0x3428));
3146 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003147}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003148
Angel Pons26681912021-01-15 21:36:28 +01003149static u8 get_bits_420(const u32 reg32)
3150{
3151 u8 val = 0;
3152 val |= (reg32 >> 4) & (1 << 0);
3153 val |= (reg32 >> 2) & (1 << 1);
3154 val |= (reg32 >> 0) & (1 << 2);
3155 return val;
3156}
3157
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003158void raminit(const int s3resume, const u8 *spd_addrmap)
3159{
Martin Roth468d02c2019-10-23 21:44:42 -06003160 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003161 struct raminfo info;
3162 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003163 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003164
Felix Held04be2dd2018-07-29 04:53:22 +02003165 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003166
3167 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3168
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003169 memset(&info, 0x5a, sizeof(info));
3170
3171 info.last_500_command[0] = 0;
3172 info.last_500_command[1] = 0;
3173
3174 info.fsb_frequency = 135 * 2;
3175 info.board_lane_delay[0] = 0x14;
3176 info.board_lane_delay[1] = 0x07;
3177 info.board_lane_delay[2] = 0x07;
3178 info.board_lane_delay[3] = 0x08;
3179 info.board_lane_delay[4] = 0x56;
3180 info.board_lane_delay[5] = 0x04;
3181 info.board_lane_delay[6] = 0x04;
3182 info.board_lane_delay[7] = 0x05;
3183 info.board_lane_delay[8] = 0x10;
3184
3185 info.training.reg_178 = 0;
3186 info.training.reg_10b = 0;
3187
Angel Ponsa3868292021-01-15 22:10:13 +01003188 /* Wait for some bit, maybe TXT clear. */
3189 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3190 ;
3191
3192 /* Wait for ME to be ready */
Angel Pons44479962021-02-24 23:08:27 +01003193 if (intel_early_me_init() == 0)
3194 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
3195 else
3196 info.memory_reserved_for_heci_mb = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003197
3198 /* before SPD */
3199 timestamp_add_now(101);
3200
Felix Held29a9c072018-07-29 01:34:45 +02003201 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003202 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3203
3204 info.use_ecc = 1;
3205 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003206 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003207 int v;
3208 int try;
3209 int addr;
3210 const u8 useful_addresses[] = {
3211 DEVICE_TYPE,
3212 MODULE_TYPE,
3213 DENSITY,
3214 RANKS_AND_DQ,
3215 MEMORY_BUS_WIDTH,
3216 TIMEBASE_DIVIDEND,
3217 TIMEBASE_DIVISOR,
3218 CYCLETIME,
3219 CAS_LATENCIES_LSB,
3220 CAS_LATENCIES_MSB,
3221 CAS_LATENCY_TIME,
3222 0x11, 0x12, 0x13, 0x14, 0x15,
3223 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3224 0x1c, 0x1d,
3225 THERMAL_AND_REFRESH,
3226 0x20,
3227 REFERENCE_RAW_CARD_USED,
3228 RANK1_ADDRESS_MAPPING,
3229 0x75, 0x76, 0x77, 0x78,
3230 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3231 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3232 0x85, 0x86, 0x87, 0x88,
3233 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3234 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3235 0x95
3236 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003237 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003238 continue;
3239 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003240 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003241 DEVICE_TYPE);
3242 if (v >= 0)
3243 break;
3244 }
3245 if (v < 0)
3246 continue;
3247 for (addr = 0;
3248 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003249 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003250 gav(info.
3251 spd[channel][0][useful_addresses
3252 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003253 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003254 useful_addresses
3255 [addr]));
3256 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3257 die("Only DDR3 is supported");
3258
3259 v = info.spd[channel][0][RANKS_AND_DQ];
3260 info.populated_ranks[channel][0][0] = 1;
3261 info.populated_ranks[channel][0][1] =
3262 ((v >> 3) & 7);
3263 if (((v >> 3) & 7) > 1)
3264 die("At most 2 ranks are supported");
3265 if ((v & 7) == 0 || (v & 7) > 2)
3266 die("Only x8 and x16 modules are supported");
3267 if ((info.
3268 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3269 && (info.
3270 spd[channel][slot][MODULE_TYPE] & 0xF)
3271 != 3)
3272 die("Registered memory is not supported");
3273 info.is_x16_module[channel][0] = (v & 7) - 1;
3274 info.density[channel][slot] =
3275 info.spd[channel][slot][DENSITY] & 0xF;
3276 if (!
3277 (info.
3278 spd[channel][slot][MEMORY_BUS_WIDTH] &
3279 0x18))
3280 info.use_ecc = 0;
3281 }
3282
3283 gav(0x55);
3284
3285 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3286 int v = 0;
3287 for (slot = 0; slot < NUM_SLOTS; slot++)
3288 for (rank = 0; rank < NUM_RANKS; rank++)
3289 v |= info.
3290 populated_ranks[channel][slot][rank]
3291 << (2 * slot + rank);
3292 info.populated_ranks_mask[channel] = v;
3293 }
3294
3295 gav(0x55);
3296
Angel Pons16fe1e02020-07-22 16:12:33 +02003297 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003298 }
3299
3300 /* after SPD */
3301 timestamp_add_now(102);
3302
Felix Held04be2dd2018-07-29 04:53:22 +02003303 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003304
3305 collect_system_info(&info);
3306 calculate_timings(&info);
3307
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003308 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003309 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003310 if (x2ca8 == 0 && (reg8 & 0x80)) {
3311 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3312 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3313 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3314 */
3315
3316 /* Clear bit7. */
3317
3318 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3319 (reg8 & ~(1 << 7)));
3320
3321 printk(BIOS_INFO,
3322 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003323 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003324 }
3325 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003326
3327 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003328 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3329 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003330
3331 compute_derived_timings(&info);
3332
Angel Pons56823f52021-01-16 11:27:33 +01003333 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003334
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003335 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003336
Angel Pons7a87c922021-01-15 22:50:41 +01003337 if (x2ca8 == 0)
3338 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003339
Angel Ponsc627dc92020-09-22 17:06:44 +02003340 MCHBAR32_OR(0x2c80, (1 << 24));
3341 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003342
Angel Ponsc627dc92020-09-22 17:06:44 +02003343 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003344
3345 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003346 MCHBAR8_AND(0x2ca8, ~3);
3347 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003348 /* This issues a CPU reset without resetting the platform */
3349 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003350 /* Write back the S3 state to PM1_CNT to let the reset CPU
3351 know it also needs to take the s3 path. */
3352 if (s3resume)
3353 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3354 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02003355 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01003356 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003357 }
Angel Pons7a87c922021-01-15 22:50:41 +01003358
Angel Ponsc627dc92020-09-22 17:06:44 +02003359 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003360
Angel Ponsc627dc92020-09-22 17:06:44 +02003361 MCHBAR32_AND(0x2c80, ~(1 << 24));
3362
Angel Pons9addda32020-07-22 18:37:32 +02003363 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003364
3365 {
3366 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
3367 u16 x2c10 = MCHBAR16(0x2c10);
3368 u16 value = MCHBAR16(0x2c00);
3369 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3370 value |= (1 << 7);
3371 else
3372 value &= ~(1 << 0);
3373
3374 MCHBAR16(0x2c00) = value;
3375 }
3376
3377 udelay(1000); // !!!!
3378
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003379 write_1d0(0, 0x33d, 0, 0);
3380 write_500(&info, 0, 0, 0xb61, 0, 0);
3381 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003382 MCHBAR32(0x1a30) = 0x0;
3383 MCHBAR32(0x1a34) = 0x0;
3384 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3385 (info.populated_ranks[0][0][0] * 0xa0);
3386 MCHBAR16(0x616) = 0x26a;
3387 MCHBAR32(0x134) = 0x856000;
3388 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02003389 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
3390 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003391 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003392 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
3393 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003394 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003395 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02003396 MCHBAR16(0x360 + (channel << 10)) = 0x909;
3397 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02003398 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
3399 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
3400 MCHBAR32(0x324 + (channel << 10)) = 0x0;
3401 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
3402 MCHBAR16(0x352 + (channel << 10)) = 0x505;
3403 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
3404 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
3405 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
3406 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
3407 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003408 }
3409
3410 write_1d0(0x4, 0x151, 4, 1);
3411 write_1d0(0, 0x142, 3, 1);
3412 rdmsr(0x1ac); // !!!!
3413 write_500(&info, 1, 1, 0x6b3, 4, 1);
3414 write_500(&info, 1, 1, 0x6cf, 4, 1);
3415
Angel Pons244f4552021-01-15 20:41:36 +01003416 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003417
3418 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3419 populated_ranks[0]
3420 [0][0]) << 0),
3421 0x1d1, 3, 1);
3422 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003423 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
3424 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003425 }
3426
3427 set_334(0);
3428
3429 program_base_timings(&info);
3430
Felix Held04be2dd2018-07-29 04:53:22 +02003431 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003432
3433 write_1d0(0x2, 0x1d5, 2, 1);
3434 write_1d0(0x20, 0x166, 7, 1);
3435 write_1d0(0x0, 0xeb, 3, 1);
3436 write_1d0(0x0, 0xf3, 6, 1);
3437
Angel Pons3d357562021-01-16 14:46:45 +01003438 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3439 u8 a = 0;
3440 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3441 a = 3;
3442 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3443 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003444
Angel Pons3d357562021-01-16 14:46:45 +01003445 for (lane = 0; lane < 9; lane++) {
3446 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3447 rmw_500(&info, channel, addr, 6, 0xf, a);
3448 }
3449 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003450
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003451 if (s3resume) {
3452 if (info.cached_training == NULL) {
3453 u32 reg32;
3454 printk(BIOS_ERR,
3455 "Couldn't find training data. Rebooting\n");
3456 reg32 = inl(DEFAULT_PMBASE + 0x04);
3457 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003458 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003459 }
3460 int tm;
3461 info.training = *info.cached_training;
3462 for (tm = 0; tm < 4; tm++)
3463 for (channel = 0; channel < NUM_CHANNELS; channel++)
3464 for (slot = 0; slot < NUM_SLOTS; slot++)
3465 for (rank = 0; rank < NUM_RANKS; rank++)
3466 for (lane = 0; lane < 9; lane++)
3467 write_500(&info,
3468 channel,
3469 info.training.
3470 lane_timings
3471 [tm][channel]
3472 [slot][rank]
3473 [lane],
3474 get_timing_register_addr
3475 (lane, tm,
3476 slot, rank),
3477 9, 0);
3478 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3479 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3480 }
3481
Felix Heldf83d80b2018-07-29 05:30:30 +02003482 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02003483 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02003484 MCHBAR8_OR(0x1f0, 0x1);
3485 while (MCHBAR8(0x1f0) & 1)
3486 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003487
3488 program_board_delay(&info);
3489
Felix Held04be2dd2018-07-29 04:53:22 +02003490 MCHBAR8(0x5ff) = 0x0;
3491 MCHBAR8(0x5ff) = 0x80;
3492 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493
Felix Held04be2dd2018-07-29 04:53:22 +02003494 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02003495 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003496 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003497
3498 rmw_1d0(0x14b, 0x47, 0x30, 7);
3499 rmw_1d0(0xd6, 0x38, 7, 6);
3500 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003501
3502 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003503 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504
Angel Ponsc627dc92020-09-22 17:06:44 +02003505 rmw_1d0(0x116, 0xe, 0, 4);
3506 rmw_1d0(0xae, 0x3e, 0, 6);
3507 rmw_1d0(0x300, 0x3e, 0, 6);
3508 MCHBAR16_AND(0x356, 0x7fff);
3509 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02003510 MCHBAR32_AND(0x140, ~0x07000000);
3511 MCHBAR32_AND(0x138, ~0x07000000);
3512 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003513 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02003514 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003515 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516
Angel Pons26681912021-01-15 21:36:28 +01003517 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003518 {
Angel Pons26681912021-01-15 21:36:28 +01003519 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3520 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3521 value_a1 = val_xa1;
3522 rmw_1d0(0x320, 0x38, val_2f3, 6);
3523 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3524 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003525 }
3526
3527 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003528 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003529
Angel Pons244f4552021-01-15 20:41:36 +01003530 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003531 {
3532 if ((MCHBAR32(0x144) & 0x1f) < 0x13)
3533 value_a1 += 2;
3534 else
3535 value_a1 += 1;
3536
3537 if (value_a1 > 7)
3538 value_a1 = 7;
3539
3540 write_1d0(2, 0xae, 6, 1);
3541 write_1d0(2, 0x300, 6, 1);
3542 write_1d0(value_a1, 0x121, 3, 1);
3543 rmw_1d0(0xd6, 0x38, 4, 6);
3544 rmw_1d0(0x328, 0x38, 4, 6);
3545 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003546
3547 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003548 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003549
Felix Held04be2dd2018-07-29 04:53:22 +02003550 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
3551 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02003552 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003553 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003554
3555 {
Angel Pons26681912021-01-15 21:36:28 +01003556 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003557 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3558 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003559 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003560 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003561
3562 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003563 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003564
3565 set_334(1);
3566
Felix Held04be2dd2018-07-29 04:53:22 +02003567 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003568
3569 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3570 write_500(&info, channel,
3571 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3572 1);
3573 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3574 }
Felix Held04be2dd2018-07-29 04:53:22 +02003575 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
3576 MCHBAR16(0x6c0) = 0x14a0;
3577 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
3578 MCHBAR16(0x232) = 0x8;
3579 /* 0x40004 or 0 depending on ? */
3580 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
3581 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
3582 MCHBAR32(0x128) = 0x2150d05;
3583 MCHBAR8(0x12c) = 0x1f;
3584 MCHBAR8(0x12d) = 0x56;
3585 MCHBAR8(0x12e) = 0x31;
3586 MCHBAR8(0x12f) = 0x0;
3587 MCHBAR8(0x271) = 0x2;
3588 MCHBAR8(0x671) = 0x2;
3589 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003590 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003591 MCHBAR32(0x294 + (channel << 10)) =
3592 (info.populated_ranks_mask[channel] & 3) << 16;
3593 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
3594 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02003596 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
3597 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598
3599 if (!s3resume)
3600 jedec_init(&info);
3601
3602 int totalrank = 0;
3603 for (channel = 0; channel < NUM_CHANNELS; channel++)
3604 for (slot = 0; slot < NUM_SLOTS; slot++)
3605 for (rank = 0; rank < NUM_RANKS; rank++)
3606 if (info.populated_ranks[channel][slot][rank]) {
3607 jedec_read(&info, channel, slot, rank,
3608 totalrank, 0xa, 0x400);
3609 totalrank++;
3610 }
3611
Felix Held04be2dd2018-07-29 04:53:22 +02003612 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613
Angel Ponsc627dc92020-09-22 17:06:44 +02003614 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
3615 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616
3617 if (!s3resume) {
3618 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003619 MCHBAR32(0x294 + (channel << 10)) =
3620 (info.populated_ranks_mask[channel] & 3) << 16;
3621 MCHBAR16(0x298 + (channel << 10)) =
3622 info.populated_ranks[channel][0][0] |
3623 (info.populated_ranks[channel][0][1] << 5);
3624 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003626 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627
3628 {
3629 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02003630 a = MCHBAR8(0x243);
3631 b = MCHBAR8(0x643);
3632 MCHBAR8(0x243) = a | 2;
3633 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634 }
3635
3636 write_1d0(7, 0x19b, 3, 1);
3637 write_1d0(7, 0x1c0, 3, 1);
3638 write_1d0(4, 0x1c6, 4, 1);
3639 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003640 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02003641 MCHBAR32(0x584) = 0xfffff;
3642 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643
3644 for (channel = 0; channel < NUM_CHANNELS; channel++)
3645 for (slot = 0; slot < NUM_SLOTS; slot++)
3646 for (rank = 0; rank < NUM_RANKS; rank++)
3647 if (info.
3648 populated_ranks[channel][slot]
3649 [rank])
3650 config_rank(&info, s3resume,
3651 channel, slot,
3652 rank);
3653
Felix Held04be2dd2018-07-29 04:53:22 +02003654 MCHBAR8(0x243) = 0x1;
3655 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656 }
3657
3658 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003659 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003660 write_26c(0, 0x820);
3661 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02003662 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663 /* end */
3664
3665 if (s3resume) {
3666 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003667 MCHBAR32(0x294 + (channel << 10)) =
3668 (info.populated_ranks_mask[channel] & 3) << 16;
3669 MCHBAR16(0x298 + (channel << 10)) =
3670 info.populated_ranks[channel][0][0] |
3671 (info.populated_ranks[channel][0][1] << 5);
3672 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003674 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675 }
3676
Felix Held04be2dd2018-07-29 04:53:22 +02003677 MCHBAR32_AND(0xfa4, ~0x01000002);
3678 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003679
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680 /* Before training. */
3681 timestamp_add_now(103);
3682
3683 if (!s3resume)
3684 ram_training(&info);
3685
3686 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003687 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003688
3689 dump_timings(&info);
3690
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691 program_modules_memory_map(&info, 0);
3692 program_total_memory_map(&info);
3693
3694 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02003695 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003696 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02003697 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02003699 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700 else
Felix Held04be2dd2018-07-29 04:53:22 +02003701 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003702
Felix Held04be2dd2018-07-29 04:53:22 +02003703 MCHBAR32_AND(0xfac, ~0x80000000);
3704 MCHBAR32(0xfb4) = 0x4800;
3705 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
3706 MCHBAR32(0xe94) = 0x7ffff;
3707 MCHBAR32(0xfc0) = 0x80002040;
3708 MCHBAR32(0xfc4) = 0x701246;
3709 MCHBAR8_AND(0xfc8, ~0x70);
3710 MCHBAR32_OR(0xe5c, 0x1000000);
3711 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
3712 MCHBAR32(0x50) = 0x700b0;
3713 MCHBAR32(0x3c) = 0x10;
3714 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
3715 MCHBAR8_OR(0xff4, 0x2);
3716 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003717
Felix Held04be2dd2018-07-29 04:53:22 +02003718 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
3719 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
3720 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003721
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003722 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3723 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3724 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003726 {
3727 u32 eax;
3728
3729 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02003730 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
3731 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
3732 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003733 }
3734
3735 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003736 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003737 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003738 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003739 else
Felix Held04be2dd2018-07-29 04:53:22 +02003740 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003741
Felix Held04be2dd2018-07-29 04:53:22 +02003742 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003743
Felix Held04be2dd2018-07-29 04:53:22 +02003744 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003745 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02003746 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747 else
Felix Held04be2dd2018-07-29 04:53:22 +02003748 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003749 }
3750
Felix Held04be2dd2018-07-29 04:53:22 +02003751 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003752
3753 {
3754 u8 al;
3755 al = 0xd;
3756 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3757 al += 2;
3758 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02003759 MCHBAR32(0x210) = (al << 16) | 0x20;
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(0x288 + (channel << 10)) = 0x70605040;
3764 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
3765 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
3766 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003767 }
3768 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003769 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003770 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003771 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003772 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003773 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003774 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02003775 MCHBAR8_OR(0x1210, 2);
3776 MCHBAR32(0x1200) = 0x8800440;
3777 MCHBAR32(0x1204) = 0x53ff0453;
3778 MCHBAR32(0x1208) = 0x19002043;
3779 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003780
3781 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02003782 MCHBAR16(0x1214) = 0x220;
3783 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003784 }
3785
Felix Held04be2dd2018-07-29 04:53:22 +02003786 MCHBAR8_OR(0x1214, 0x4);
3787 MCHBAR8(0x120c) = 0x1;
3788 MCHBAR8(0x1218) = 0x3;
3789 MCHBAR8(0x121a) = 0x3;
3790 MCHBAR8(0x121c) = 0x3;
3791 MCHBAR16(0xc14) = 0x0;
3792 MCHBAR16(0xc20) = 0x0;
3793 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003794
3795 /* revision dependent here. */
3796
Felix Held04be2dd2018-07-29 04:53:22 +02003797 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003798
3799 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02003800 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003801
Felix Held04be2dd2018-07-29 04:53:22 +02003802 MCHBAR16_OR(0x1230, 0x8000);
3803 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003804
3805 u8 bl, ebpb;
3806 u16 reg_1020;
3807
Felix Held04be2dd2018-07-29 04:53:22 +02003808 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
3809 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003810
Felix Held04be2dd2018-07-29 04:53:22 +02003811 MCHBAR32(0x1000) = 0x100;
3812 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003813
3814 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003815 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003816 bl = reg_1020 >> 8;
3817 ebpb = reg_1020 & 0xff;
3818 } else {
3819 ebpb = 0;
3820 bl = 8;
3821 }
3822
3823 rdmsr(0x1a2);
3824
Felix Held04be2dd2018-07-29 04:53:22 +02003825 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003826
Felix Held04be2dd2018-07-29 04:53:22 +02003827 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003828
Felix Held04be2dd2018-07-29 04:53:22 +02003829 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003830
Felix Held04be2dd2018-07-29 04:53:22 +02003831 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003832 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003833 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
3834 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835 }
3836
3837 setup_heci_uma(&info);
3838
3839 if (info.uma_enabled) {
3840 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02003841 MCHBAR32_OR(0x11b0, 0x4000);
3842 MCHBAR32_OR(0x11b4, 0x4000);
3843 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003844
Felix Held04be2dd2018-07-29 04:53:22 +02003845 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
3846 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
3847 MCHBAR16_OR(0x1170, 0x1000);
3848
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003849 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003850
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02003852 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003853 ;
3854 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855 }
3856
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003857 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3858 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02003860 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862 udelay(1000);
3863 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003864 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3865
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003866 if (!s3resume)
3867 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003868 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003869 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003870 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003871
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003872 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003873 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003874 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875}