blob: e3b0b3363a8d23eb569ee2e48486052ebfca953e [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)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010038
39#define FOR_ALL_RANKS \
40 for (channel = 0; channel < NUM_CHANNELS; channel++) \
41 for (slot = 0; slot < NUM_SLOTS; slot++) \
42 for (rank = 0; rank < NUM_RANKS; rank++)
43
44#define FOR_POPULATED_RANKS \
45 for (channel = 0; channel < NUM_CHANNELS; channel++) \
46 for (slot = 0; slot < NUM_SLOTS; slot++) \
47 for (rank = 0; rank < NUM_RANKS; rank++) \
48 if (info->populated_ranks[channel][slot][rank])
49
50#define FOR_POPULATED_RANKS_BACKWARDS \
51 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
52 for (slot = 0; slot < NUM_SLOTS; slot++) \
53 for (rank = 0; rank < NUM_RANKS; rank++) \
54 if (info->populated_ranks[channel][slot][rank])
55
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010056#include <lib.h> /* Prototypes */
57
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010058typedef struct _u128 {
59 u64 lo;
60 u64 hi;
61} u128;
62
63static void read128(u32 addr, u64 * out)
64{
65 u128 ret;
66 u128 stor;
67 asm volatile ("movdqu %%xmm0, %0\n"
68 "movdqa (%2), %%xmm0\n"
69 "movdqu %%xmm0, %1\n"
70 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
71 out[0] = ret.lo;
72 out[1] = ret.hi;
73}
74
Angel Ponsc2d6f5f2020-12-11 23:48:51 +010075/*
76 * Ironlake memory I/O timings are located in scan chains, accessible
77 * through MCHBAR register groups. Each channel has a scan chain, and
78 * there's a global scan chain too. Each chain is broken into smaller
79 * sections of N bits, where N <= 32. Each section allows reading and
80 * writing a certain parameter. Each section contains N - 2 data bits
81 * and two additional bits: a Mask bit, and a Halt bit.
82 */
83
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010084/* OK */
85static void write_1d0(u32 val, u16 addr, int bits, int flag)
86{
Angel Ponsdea722b2021-03-26 14:11:12 +010087 mchbar_write32(0x1d0, 0);
88 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +020089 ;
Angel Ponsdea722b2021-03-26 14:11:12 +010090 mchbar_write32(0x1d4, (val & ((1 << bits) - 1)) | 2 << bits | flag << bits);
91 mchbar_write32(0x1d0, 1 << 30 | addr);
92 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +020093 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094}
95
96/* OK */
97static u16 read_1d0(u16 addr, int split)
98{
99 u32 val;
Angel Ponsdea722b2021-03-26 14:11:12 +0100100 mchbar_write32(0x1d0, 0);
101 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200102 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100103 mchbar_write32(0x1d0, 1 << 31 | (((mchbar_read8(0x246) >> 2) & 3) + 0x361 - addr));
104 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200105 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100106 val = mchbar_read32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100107 write_1d0(0, 0x33d, 0, 0);
108 write_1d0(0, 0x33d, 0, 0);
109 val &= ((1 << split) - 1);
110 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
111 return val;
112}
113
114static void sfence(void)
115{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100116 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100117}
118
119static inline u16 get_lane_offset(int slot, int rank, int lane)
120{
121 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
122 0x452 * (lane == 8);
123}
124
125static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
126{
127 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
128 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
129}
130
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100131static u32 gav_real(int line, u32 in)
132{
133 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
134 return in;
135}
136
137#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200138
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200139/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100140timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200141
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100142/* OK */
143static u16
144read_500(struct raminfo *info, int channel, u16 addr, int split)
145{
146 u32 val;
Angel Ponsdea722b2021-03-26 14:11:12 +0100147 info->last_500_command[channel] = 1 << 31;
148 mchbar_write32(0x500 + (channel << 10), 0);
149 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200150 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100151 mchbar_write32(0x500 + (channel << 10),
152 1 << 31 | (((mchbar_read8(0x246 + (channel << 10)) >> 2) & 3) + 0xb88 - addr));
153 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200154 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100155 val = mchbar_read32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100156 return val & ((1 << split) - 1);
157}
158
159/* OK */
160static void
161write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
162 int flag)
163{
Angel Ponsdea722b2021-03-26 14:11:12 +0100164 if (info->last_500_command[channel] == 1 << 31) {
165 info->last_500_command[channel] = 1 << 30;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100166 write_500(info, channel, 0, 0xb61, 0, 0);
167 }
Angel Ponsdea722b2021-03-26 14:11:12 +0100168 mchbar_write32(0x500 + (channel << 10), 0);
169 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200170 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100171 mchbar_write32(0x504 + (channel << 10),
172 (val & ((1 << bits) - 1)) | 2 << bits | flag << bits);
173 mchbar_write32(0x500 + (channel << 10), 1 << 30 | addr);
174 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200175 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100176}
177
Angel Ponsc10f8b22021-01-15 20:34:51 +0100178static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
179{
180 const u32 val = read_500(info, channel, addr, bits) & and;
181 write_500(info, channel, val | or, addr, bits, 1);
182}
183
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100184static int rw_test(int rank)
185{
186 const u32 mask = 0xf00fc33c;
187 int ok = 0xff;
188 int i;
189 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800190 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100191 sfence();
192 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800193 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100194 sfence();
195 for (i = 0; i < 32; i++) {
196 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800197 write32p((rank << 28) | (i << 3), pat);
198 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100199 }
200 sfence();
201 for (i = 0; i < 32; i++) {
202 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
203 int j;
204 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800205 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100206 for (j = 0; j < 4; j++)
207 if (((val >> (j * 8)) & 0xff) != pat)
208 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800209 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100210 for (j = 0; j < 4; j++)
211 if (((val >> (j * 8)) & 0xff) != pat)
212 ok &= ~(16 << j);
213 }
214 sfence();
215 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800216 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100217 sfence();
218 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800219 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100220
221 return ok;
222}
223
224static void
225program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
226{
227 int lane;
228 for (lane = 0; lane < 8; lane++) {
229 write_500(info, channel,
230 base +
231 info->training.
232 lane_timings[2][channel][slot][rank][lane],
233 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
234 write_500(info, channel,
235 base +
236 info->training.
237 lane_timings[3][channel][slot][rank][lane],
238 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
239 }
240}
241
242static void write_26c(int channel, u16 si)
243{
Angel Ponsdea722b2021-03-26 14:11:12 +0100244 mchbar_write32(0x26c + (channel << 10), 0x03243f35);
245 mchbar_write32(0x268 + (channel << 10), 0xcfc00000 | si << 9);
246 mchbar_write16(0x2b9 + (channel << 10), si);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100247}
248
Angel Ponsc627dc92020-09-22 17:06:44 +0200249static void toggle_1d0_142_5ff(void)
250{
251 u32 reg32 = gav(read_1d0(0x142, 3));
252 if (reg32 & (1 << 1))
253 write_1d0(0, 0x142, 3, 1);
254
Angel Ponsdea722b2021-03-26 14:11:12 +0100255 mchbar_write8(0x5ff, 0);
256 mchbar_write8(0x5ff, 1 << 7);
Angel Ponsc627dc92020-09-22 17:06:44 +0200257 if (reg32 & (1 << 1))
258 write_1d0(0x2, 0x142, 3, 1);
259}
260
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100261static u32 get_580(int channel, u8 addr)
262{
263 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200264 toggle_1d0_142_5ff();
Angel Ponsdea722b2021-03-26 14:11:12 +0100265 mchbar_write32(0x580 + (channel << 10), 0x8493c012 | addr);
266 mchbar_setbits8(0x580 + (channel << 10), 1 << 0);
267 while (!((ret = mchbar_read32(0x580 + (channel << 10))) & (1 << 16)))
Felix Held04be2dd2018-07-29 04:53:22 +0200268 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100269 mchbar_clrbits8(0x580 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270 return ret;
271}
272
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100273#define RANK_SHIFT 28
274#define CHANNEL_SHIFT 10
275
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276static void seq9(struct raminfo *info, int channel, int slot, int rank)
277{
278 int i, lane;
279
280 for (i = 0; i < 2; i++)
281 for (lane = 0; lane < 8; lane++)
282 write_500(info, channel,
283 info->training.lane_timings[i +
284 1][channel][slot]
285 [rank][lane], get_timing_register_addr(lane,
286 i + 1,
287 slot,
288 rank),
289 9, 0);
290
291 write_1d0(1, 0x103, 6, 1);
292 for (lane = 0; lane < 8; lane++)
293 write_500(info, channel,
294 info->training.
295 lane_timings[0][channel][slot][rank][lane],
296 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
297
298 for (i = 0; i < 2; i++) {
299 for (lane = 0; lane < 8; lane++)
300 write_500(info, channel,
301 info->training.lane_timings[i +
302 1][channel][slot]
303 [rank][lane], get_timing_register_addr(lane,
304 i + 1,
305 slot,
306 rank),
307 9, 0);
308 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
309 }
310
Angel Ponsc627dc92020-09-22 17:06:44 +0200311 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100312 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200313
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100314 for (lane = 0; lane < 8; lane++) {
315 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
316 info->training.lane_timings[2][channel][slot][rank][lane] =
317 read_500(info, channel,
318 get_timing_register_addr(lane, 2, slot, rank), 9);
319 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
320 info->training.lane_timings[3][channel][slot][rank][lane] =
321 info->training.lane_timings[2][channel][slot][rank][lane] +
322 0x20;
323 }
324}
325
326static int count_ranks_in_channel(struct raminfo *info, int channel)
327{
328 int slot, rank;
329 int res = 0;
330 for (slot = 0; slot < NUM_SLOTS; slot++)
331 for (rank = 0; rank < NUM_SLOTS; rank++)
332 res += info->populated_ranks[channel][slot][rank];
333 return res;
334}
335
336static void
337config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
338{
339 int add;
340
341 write_1d0(0, 0x178, 7, 1);
342 seq9(info, channel, slot, rank);
343 program_timings(info, 0x80, channel, slot, rank);
344
345 if (channel == 0)
346 add = count_ranks_in_channel(info, 1);
347 else
348 add = 0;
349 if (!s3resume)
350 gav(rw_test(rank + add));
351 program_timings(info, 0x00, channel, slot, rank);
352 if (!s3resume)
353 gav(rw_test(rank + add));
354 if (!s3resume)
355 gav(rw_test(rank + add));
356 write_1d0(0, 0x142, 3, 1);
357 write_1d0(0, 0x103, 6, 1);
358
359 gav(get_580(channel, 0xc | (rank << 5)));
360 gav(read_1d0(0x142, 3));
361
Angel Ponsdea722b2021-03-26 14:11:12 +0100362 mchbar_write8(0x5ff, 0);
363 mchbar_write8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100364}
365
Angel Ponsc10f8b22021-01-15 20:34:51 +0100366static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100367{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100368 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
369
370 val &= 1;
371 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
372 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100373}
374
375static void set_334(int zero)
376{
377 int j, k, channel;
378 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
379 u32 vd8[2][16];
380
381 for (channel = 0; channel < NUM_CHANNELS; channel++) {
382 for (j = 0; j < 4; j++) {
383 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
384 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
385 u16 c;
386 if ((j == 0 || j == 3) && zero)
387 c = 0;
388 else if (j == 3)
389 c = 0x5f;
390 else
391 c = 0x5f5f;
392
393 for (k = 0; k < 2; k++) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100394 mchbar_write32(0x138 + 8 * k, channel << 26 | j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100395 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Angel Ponsdea722b2021-03-26 14:11:12 +0100396 mchbar_read32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100397 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Angel Ponsdea722b2021-03-26 14:11:12 +0100398 mchbar_read32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100399 }
400
Angel Ponsdea722b2021-03-26 14:11:12 +0100401 mchbar_write32(0x334 + (channel << 10) + j * 0x44, zero ? 0 : val3[j]);
402 mchbar_write32(0x32c + (channel << 10) + j * 0x44,
403 zero ? 0 : 0x18191819 & lmask);
404 mchbar_write16(0x34a + (channel << 10) + j * 0x44, c);
405 mchbar_write32(0x33c + (channel << 10) + j * 0x44,
406 zero ? 0 : a & lmask);
407 mchbar_write32(0x344 + (channel << 10) + j * 0x44,
408 zero ? 0 : a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100409 }
410 }
411
Angel Ponsdea722b2021-03-26 14:11:12 +0100412 mchbar_setbits32(0x130, 1 << 0);
413 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +0200414 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100415}
416
Angel Pons244f4552021-01-15 20:41:36 +0100417static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100418{
419 u32 v;
420 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100421 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100422}
423
424static int find_highest_bit_set(u16 val)
425{
426 int i;
427 for (i = 15; i >= 0; i--)
428 if (val & (1 << i))
429 return i;
430 return -1;
431}
432
433static int find_lowest_bit_set32(u32 val)
434{
435 int i;
436 for (i = 0; i < 32; i++)
437 if (val & (1 << i))
438 return i;
439 return -1;
440}
441
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100442enum {
443 DEVICE_TYPE = 2,
444 MODULE_TYPE = 3,
445 DENSITY = 4,
446 RANKS_AND_DQ = 7,
447 MEMORY_BUS_WIDTH = 8,
448 TIMEBASE_DIVIDEND = 10,
449 TIMEBASE_DIVISOR = 11,
450 CYCLETIME = 12,
451
452 CAS_LATENCIES_LSB = 14,
453 CAS_LATENCIES_MSB = 15,
454 CAS_LATENCY_TIME = 16,
455 THERMAL_AND_REFRESH = 31,
456 REFERENCE_RAW_CARD_USED = 62,
457 RANK1_ADDRESS_MAPPING = 63
458};
459
460static void calculate_timings(struct raminfo *info)
461{
Martin Roth468d02c2019-10-23 21:44:42 -0600462 unsigned int cycletime;
463 unsigned int cas_latency_time;
464 unsigned int supported_cas_latencies;
465 unsigned int channel, slot;
466 unsigned int clock_speed_index;
467 unsigned int min_cas_latency;
468 unsigned int cas_latency;
469 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100470
471 /* Find common CAS latency */
472 supported_cas_latencies = 0x3fe;
473 for (channel = 0; channel < NUM_CHANNELS; channel++)
474 for (slot = 0; slot < NUM_SLOTS; slot++)
475 if (info->populated_ranks[channel][slot][0])
476 supported_cas_latencies &=
477 2 *
478 (info->
479 spd[channel][slot][CAS_LATENCIES_LSB] |
480 (info->
481 spd[channel][slot][CAS_LATENCIES_MSB] <<
482 8));
483
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100484 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485
486 cycletime = min_cycletime[max_clock_index];
487 cas_latency_time = min_cas_latency_time[max_clock_index];
488
489 for (channel = 0; channel < NUM_CHANNELS; channel++)
490 for (slot = 0; slot < NUM_SLOTS; slot++)
491 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600492 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100493 timebase =
494 1000 *
495 info->
496 spd[channel][slot][TIMEBASE_DIVIDEND] /
497 info->spd[channel][slot][TIMEBASE_DIVISOR];
498 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100499 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100500 timebase *
501 info->spd[channel][slot][CYCLETIME]);
502 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100503 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100504 timebase *
505 info->
506 spd[channel][slot][CAS_LATENCY_TIME]);
507 }
Jacob Garber3c193822019-06-10 18:23:32 -0600508 if (cycletime > min_cycletime[0])
509 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100510 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
511 if (cycletime == min_cycletime[clock_speed_index])
512 break;
513 if (cycletime > min_cycletime[clock_speed_index]) {
514 clock_speed_index--;
515 cycletime = min_cycletime[clock_speed_index];
516 break;
517 }
518 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100519 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100520 cas_latency = 0;
521 while (supported_cas_latencies) {
522 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
523 if (cas_latency <= min_cas_latency)
524 break;
525 supported_cas_latencies &=
526 ~(1 << find_highest_bit_set(supported_cas_latencies));
527 }
528
529 if (cas_latency != min_cas_latency && clock_speed_index)
530 clock_speed_index--;
531
532 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
533 die("Couldn't configure DRAM");
534 info->clock_speed_index = clock_speed_index;
535 info->cas_latency = cas_latency;
536}
537
538static void program_base_timings(struct raminfo *info)
539{
Martin Roth468d02c2019-10-23 21:44:42 -0600540 unsigned int channel;
541 unsigned int slot, rank, lane;
542 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100543 int i;
544
545 extended_silicon_revision = info->silicon_revision;
546 if (info->silicon_revision == 0)
547 for (channel = 0; channel < NUM_CHANNELS; channel++)
548 for (slot = 0; slot < NUM_SLOTS; slot++)
549 if ((info->
550 spd[channel][slot][MODULE_TYPE] & 0xF) ==
551 3)
552 extended_silicon_revision = 4;
553
554 for (channel = 0; channel < NUM_CHANNELS; channel++) {
555 for (slot = 0; slot < NUM_SLOTS; slot++)
556 for (rank = 0; rank < NUM_SLOTS; rank++) {
557 int card_timing_2;
558 if (!info->populated_ranks[channel][slot][rank])
559 continue;
560
561 for (lane = 0; lane < 9; lane++) {
562 int tm_reg;
563 int card_timing;
564
565 card_timing = 0;
566 if ((info->
567 spd[channel][slot][MODULE_TYPE] &
568 0xF) == 3) {
569 int reference_card;
570 reference_card =
571 info->
572 spd[channel][slot]
573 [REFERENCE_RAW_CARD_USED] &
574 0x1f;
575 if (reference_card == 3)
576 card_timing =
577 u16_ffd1188[0][lane]
578 [info->
579 clock_speed_index];
580 if (reference_card == 5)
581 card_timing =
582 u16_ffd1188[1][lane]
583 [info->
584 clock_speed_index];
585 }
586
587 info->training.
588 lane_timings[0][channel][slot][rank]
589 [lane] =
590 u8_FFFD1218[info->
591 clock_speed_index];
592 info->training.
593 lane_timings[1][channel][slot][rank]
594 [lane] = 256;
595
596 for (tm_reg = 2; tm_reg < 4; tm_reg++)
597 info->training.
598 lane_timings[tm_reg]
599 [channel][slot][rank][lane]
600 =
601 u8_FFFD1240[channel]
602 [extended_silicon_revision]
603 [lane][2 * slot +
604 rank][info->
605 clock_speed_index]
606 + info->max4048[channel]
607 +
608 u8_FFFD0C78[channel]
609 [extended_silicon_revision]
610 [info->
611 mode4030[channel]][slot]
612 [rank][info->
613 clock_speed_index]
614 + card_timing;
615 for (tm_reg = 0; tm_reg < 4; tm_reg++)
616 write_500(info, channel,
617 info->training.
618 lane_timings[tm_reg]
619 [channel][slot][rank]
620 [lane],
621 get_timing_register_addr
622 (lane, tm_reg, slot,
623 rank), 9, 0);
624 }
625
626 card_timing_2 = 0;
627 if (!(extended_silicon_revision != 4
628 || (info->
629 populated_ranks_mask[channel] & 5) ==
630 5)) {
631 if ((info->
632 spd[channel][slot]
633 [REFERENCE_RAW_CARD_USED] & 0x1F)
634 == 3)
635 card_timing_2 =
636 u16_FFFE0EB8[0][info->
637 clock_speed_index];
638 if ((info->
639 spd[channel][slot]
640 [REFERENCE_RAW_CARD_USED] & 0x1F)
641 == 5)
642 card_timing_2 =
643 u16_FFFE0EB8[1][info->
644 clock_speed_index];
645 }
646
647 for (i = 0; i < 3; i++)
648 write_500(info, channel,
649 (card_timing_2 +
650 info->max4048[channel]
651 +
652 u8_FFFD0EF8[channel]
653 [extended_silicon_revision]
654 [info->
655 mode4030[channel]][info->
656 clock_speed_index]),
657 u16_fffd0c50[i][slot][rank],
658 8, 1);
659 write_500(info, channel,
660 (info->max4048[channel] +
661 u8_FFFD0C78[channel]
662 [extended_silicon_revision][info->
663 mode4030
664 [channel]]
665 [slot][rank][info->
666 clock_speed_index]),
667 u16_fffd0c70[slot][rank], 7, 1);
668 }
669 if (!info->populated_ranks_mask[channel])
670 continue;
671 for (i = 0; i < 3; i++)
672 write_500(info, channel,
673 (info->max4048[channel] +
674 info->avg4044[channel]
675 +
676 u8_FFFD17E0[channel]
677 [extended_silicon_revision][info->
678 mode4030
679 [channel]][info->
680 clock_speed_index]),
681 u16_fffd0c68[i], 8, 1);
682 }
683}
684
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100685/* The time of clock cycle in ps. */
686static unsigned int cycle_ps(struct raminfo *info)
687{
688 return 2 * halfcycle_ps(info);
689}
690
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100691/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600692static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100693{
694 return 100 * frequency_11(info) / 9;
695}
696
Martin Roth468d02c2019-10-23 21:44:42 -0600697static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100698{
699 return (frequency_11(info) * 2) * ps / 900000;
700}
701
Martin Roth468d02c2019-10-23 21:44:42 -0600702static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100703{
704 return (frequency_11(info)) * ns / 900;
705}
706
707static void compute_derived_timings(struct raminfo *info)
708{
Martin Roth468d02c2019-10-23 21:44:42 -0600709 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100710 int extended_silicon_revision;
711 int some_delay_1_ps;
712 int some_delay_2_ps;
713 int some_delay_2_halfcycles_ceil;
714 int some_delay_2_halfcycles_floor;
715 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100716 int some_delay_3_ps_rounded;
717 int some_delay_1_cycle_ceil;
718 int some_delay_1_cycle_floor;
719
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100720 some_delay_3_ps_rounded = 0;
721 extended_silicon_revision = info->silicon_revision;
722 if (!info->silicon_revision)
723 for (channel = 0; channel < NUM_CHANNELS; channel++)
724 for (slot = 0; slot < NUM_SLOTS; slot++)
725 if ((info->
726 spd[channel][slot][MODULE_TYPE] & 0xF) ==
727 3)
728 extended_silicon_revision = 4;
729 if (info->board_lane_delay[7] < 5)
730 info->board_lane_delay[7] = 5;
731 info->revision_flag_1 = 2;
732 if (info->silicon_revision == 2 || info->silicon_revision == 3)
733 info->revision_flag_1 = 0;
734 if (info->revision < 16)
735 info->revision_flag_1 = 0;
736
737 if (info->revision < 8)
738 info->revision_flag_1 = 0;
739 if (info->revision >= 8 && (info->silicon_revision == 0
740 || info->silicon_revision == 1))
741 some_delay_2_ps = 735;
742 else
743 some_delay_2_ps = 750;
744
745 if (info->revision >= 0x10 && (info->silicon_revision == 0
746 || info->silicon_revision == 1))
747 some_delay_1_ps = 3929;
748 else
749 some_delay_1_ps = 3490;
750
751 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
752 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
753 if (some_delay_1_ps % cycle_ps(info))
754 some_delay_1_cycle_ceil++;
755 else
756 some_delay_1_cycle_floor--;
757 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
758 if (info->revision_flag_1)
759 some_delay_2_ps = halfcycle_ps(info) >> 6;
760 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100761 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100762 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
763 375;
764 some_delay_3_ps =
765 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
766 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200767 if (some_delay_3_ps >= 150) {
768 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100769 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200770 some_delay_3_ps_rounded =
771 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
772 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100773 }
774 some_delay_2_halfcycles_ceil =
775 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
776 2 * (some_delay_1_cycle_ceil - 1);
777 if (info->revision_flag_1 && some_delay_3_ps < 150)
778 some_delay_2_halfcycles_ceil++;
779 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
780 if (info->revision < 0x10)
781 some_delay_2_halfcycles_floor =
782 some_delay_2_halfcycles_ceil - 1;
783 if (!info->revision_flag_1)
784 some_delay_2_halfcycles_floor++;
Arthur Heymansb291dc82022-11-04 20:56:32 +0100785 /* FIXME: this variable is unused. Should it be used? */
786 (void)some_delay_2_halfcycles_floor;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100787 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
788 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
789 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
790 || (info->populated_ranks[1][0][0]
791 && info->populated_ranks[1][1][0]))
792 info->max_slots_used_in_channel = 2;
793 else
794 info->max_slots_used_in_channel = 1;
Angel Pons2ea8b942021-12-19 17:15:48 +0100795 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +0100796 mchbar_write32(0x244 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +0200797 ((info->revision < 8) ? 1 : 0x200) |
798 ((2 - info->max_slots_used_in_channel) << 17) |
799 (channel << 21) |
Angel Ponsdea722b2021-03-26 14:11:12 +0100800 (info->some_delay_1_cycle_floor << 18) | 0x9510);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100801 if (info->max_slots_used_in_channel == 1) {
802 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
803 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
804 } else {
805 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 */
806 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
807 || (count_ranks_in_channel(info, 1) ==
808 2)) ? 2 : 3;
809 }
810 for (channel = 0; channel < NUM_CHANNELS; channel++) {
811 int max_of_unk;
812 int min_of_unk_2;
813
814 int i, count;
815 int sum;
816
817 if (!info->populated_ranks_mask[channel])
818 continue;
819
820 max_of_unk = 0;
821 min_of_unk_2 = 32767;
822
823 sum = 0;
824 count = 0;
825 for (i = 0; i < 3; i++) {
826 int unk1;
827 if (info->revision < 8)
828 unk1 =
829 u8_FFFD1891[0][channel][info->
830 clock_speed_index]
831 [i];
832 else if (!
833 (info->revision >= 0x10
834 || info->revision_flag_1))
835 unk1 =
836 u8_FFFD1891[1][channel][info->
837 clock_speed_index]
838 [i];
839 else
840 unk1 = 0;
841 for (slot = 0; slot < NUM_SLOTS; slot++)
842 for (rank = 0; rank < NUM_RANKS; rank++) {
843 int a = 0;
844 int b = 0;
845
846 if (!info->
847 populated_ranks[channel][slot]
848 [rank])
849 continue;
850 if (extended_silicon_revision == 4
851 && (info->
852 populated_ranks_mask[channel] &
853 5) != 5) {
854 if ((info->
855 spd[channel][slot]
856 [REFERENCE_RAW_CARD_USED] &
857 0x1F) == 3) {
858 a = u16_ffd1178[0]
859 [info->
860 clock_speed_index];
861 b = u16_fe0eb8[0][info->
862 clock_speed_index];
863 } else
864 if ((info->
865 spd[channel][slot]
866 [REFERENCE_RAW_CARD_USED]
867 & 0x1F) == 5) {
868 a = u16_ffd1178[1]
869 [info->
870 clock_speed_index];
871 b = u16_fe0eb8[1][info->
872 clock_speed_index];
873 }
874 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100875 min_of_unk_2 = MIN(min_of_unk_2, a);
876 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100877 if (rank == 0) {
878 sum += a;
879 count++;
880 }
881 {
882 int t;
883 t = b +
884 u8_FFFD0EF8[channel]
885 [extended_silicon_revision]
886 [info->
887 mode4030[channel]][info->
888 clock_speed_index];
889 if (unk1 >= t)
890 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100891 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 unk1 - t);
893 }
894 }
895 {
896 int t =
897 u8_FFFD17E0[channel]
898 [extended_silicon_revision][info->
899 mode4030
900 [channel]]
901 [info->clock_speed_index] + min_of_unk_2;
902 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100903 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100904 }
905 }
906
Jacob Garber64fb4a32019-06-10 17:29:18 -0600907 if (count == 0)
908 die("No memory ranks found for channel %u\n", channel);
909
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100910 info->avg4044[channel] = sum / count;
911 info->max4048[channel] = max_of_unk;
912 }
913}
914
915static void jedec_read(struct raminfo *info,
916 int channel, int slot, int rank,
917 int total_rank, u8 addr3, unsigned int value)
918{
919 /* Handle mirrored mapping. */
Angel Pons4cee77b2022-02-14 14:12:52 +0100920 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1)) {
921 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) | ((addr3 >> 1) & 0x10);
922 value = (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8) << 1);
923 }
Angel Ponsdea722b2021-03-26 14:11:12 +0100924
925 mchbar_clrsetbits8(0x271, 0x1f << 1, addr3);
926 mchbar_clrsetbits8(0x671, 0x1f << 1, addr3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100927
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800928 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100929
Angel Ponsdea722b2021-03-26 14:11:12 +0100930 mchbar_clrsetbits8(0x271, 0x1f << 1, 1 << 1);
931 mchbar_clrsetbits8(0x671, 0x1f << 1, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100932
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800933 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100934}
935
936enum {
937 MR1_RZQ12 = 512,
938 MR1_RZQ2 = 64,
939 MR1_RZQ4 = 4,
940 MR1_ODS34OHM = 2
941};
942
943enum {
944 MR0_BT_INTERLEAVED = 8,
945 MR0_DLL_RESET_ON = 256
946};
947
948enum {
949 MR2_RTT_WR_DISABLED = 0,
950 MR2_RZQ2 = 1 << 10
951};
952
953static void jedec_init(struct raminfo *info)
954{
955 int write_recovery;
956 int channel, slot, rank;
957 int total_rank;
958 int dll_on;
959 int self_refresh_temperature;
960 int auto_self_refresh;
961
962 auto_self_refresh = 1;
963 self_refresh_temperature = 1;
964 if (info->board_lane_delay[3] <= 10) {
965 if (info->board_lane_delay[3] <= 8)
966 write_recovery = info->board_lane_delay[3] - 4;
967 else
968 write_recovery = 5;
969 } else {
970 write_recovery = 6;
971 }
972 FOR_POPULATED_RANKS {
973 auto_self_refresh &=
974 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
975 self_refresh_temperature &=
976 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
977 }
978 if (auto_self_refresh == 1)
979 self_refresh_temperature = 0;
980
981 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
982 || (info->populated_ranks[0][0][0]
983 && info->populated_ranks[0][1][0])
984 || (info->populated_ranks[1][0][0]
985 && info->populated_ranks[1][1][0]));
986
987 total_rank = 0;
988
989 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
990 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
991 int rzq_reg58e;
992
993 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
994 rzq_reg58e = 64;
995 rtt = MR1_RZQ2;
996 if (info->clock_speed_index != 0) {
997 rzq_reg58e = 4;
998 if (info->populated_ranks_mask[channel] == 3)
999 rtt = MR1_RZQ4;
1000 }
1001 } else {
1002 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1003 rtt = MR1_RZQ12;
1004 rzq_reg58e = 64;
1005 rtt_wr = MR2_RZQ2;
1006 } else {
1007 rzq_reg58e = 4;
1008 rtt = MR1_RZQ4;
1009 }
1010 }
1011
Angel Ponsdea722b2021-03-26 14:11:12 +01001012 mchbar_write16(0x588 + (channel << 10), 0);
1013 mchbar_write16(0x58a + (channel << 10), 4);
1014 mchbar_write16(0x58c + (channel << 10), rtt | MR1_ODS34OHM);
1015 mchbar_write16(0x58e + (channel << 10), rzq_reg58e | 0x82);
1016 mchbar_write16(0x590 + (channel << 10), 0x1282);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001017
1018 for (slot = 0; slot < NUM_SLOTS; slot++)
1019 for (rank = 0; rank < NUM_RANKS; rank++)
1020 if (info->populated_ranks[channel][slot][rank]) {
1021 jedec_read(info, channel, slot, rank,
1022 total_rank, 0x28,
1023 rtt_wr | (info->
1024 clock_speed_index
1025 << 3)
1026 | (auto_self_refresh << 6) |
1027 (self_refresh_temperature <<
1028 7));
1029 jedec_read(info, channel, slot, rank,
1030 total_rank, 0x38, 0);
1031 jedec_read(info, channel, slot, rank,
1032 total_rank, 0x18,
1033 rtt | MR1_ODS34OHM);
1034 jedec_read(info, channel, slot, rank,
1035 total_rank, 6,
1036 (dll_on << 12) |
1037 (write_recovery << 9)
1038 | ((info->cas_latency - 4) <<
1039 4) | MR0_BT_INTERLEAVED |
1040 MR0_DLL_RESET_ON);
1041 total_rank++;
1042 }
1043 }
1044}
1045
1046static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1047{
Martin Roth468d02c2019-10-23 21:44:42 -06001048 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001049 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1050 unsigned int channel_0_non_interleaved;
1051
1052 FOR_ALL_RANKS {
1053 if (info->populated_ranks[channel][slot][rank]) {
1054 total_mb[channel] +=
1055 pre_jedec ? 256 : (256 << info->
1056 density[channel][slot] >> info->
1057 is_x16_module[channel][slot]);
Angel Ponsdea722b2021-03-26 14:11:12 +01001058 mchbar_write8(0x208 + rank + 2 * slot + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001059 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1060 (info->is_x16_module[channel][slot] |
1061 ((info->density[channel][slot] + 1) << 1))) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001062 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001063 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001064 mchbar_write16(0x200 + (channel << 10) + 4 * slot + 2 * rank,
1065 total_mb[channel] >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001066 }
1067
1068 info->total_memory_mb = total_mb[0] + total_mb[1];
1069
1070 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001071 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001072 info->non_interleaved_part_mb =
1073 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1074 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001075 mchbar_write32(0x100, channel_0_non_interleaved | info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001076 if (!pre_jedec)
Angel Ponsdea722b2021-03-26 14:11:12 +01001077 mchbar_write16(0x104, info->interleaved_part_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001078}
1079
1080static void program_board_delay(struct raminfo *info)
1081{
1082 int cas_latency_shift;
1083 int some_delay_ns;
1084 int some_delay_3_half_cycles;
1085
Martin Roth468d02c2019-10-23 21:44:42 -06001086 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001087 int high_multiplier;
1088 int lane_3_delay;
1089 int cas_latency_derived;
1090
1091 high_multiplier = 0;
1092 some_delay_ns = 200;
1093 some_delay_3_half_cycles = 4;
1094 cas_latency_shift = info->silicon_revision == 0
1095 || info->silicon_revision == 1 ? 1 : 0;
1096 if (info->revision < 8) {
1097 some_delay_ns = 600;
1098 cas_latency_shift = 0;
1099 }
1100 {
1101 int speed_bit;
1102 speed_bit =
1103 ((info->clock_speed_index > 1
1104 || (info->silicon_revision != 2
1105 && info->silicon_revision != 3))) ^ (info->revision >=
1106 0x10);
1107 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1108 3, 1);
1109 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1110 3, 1);
1111 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1112 && (info->silicon_revision == 2
1113 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001114 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001115 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001116 mchbar_write32(0x120, 1 << (info->max_slots_used_in_channel + 28) | 0x188e7f9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001117
Angel Ponsdea722b2021-03-26 14:11:12 +01001118 mchbar_write8(0x124, info->board_lane_delay[4] + (frequency_01(info) + 999) / 1000);
1119 mchbar_write16(0x125, 0x1360);
1120 mchbar_write8(0x127, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001121 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001122 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001123 high_multiplier = 1;
1124 some_delay_2_half_cycles = ps_to_halfcycles(info,
1125 ((3 *
1126 fsbcycle_ps(info))
1127 >> 1) +
1128 (halfcycle_ps(info)
1129 *
1130 reg178_min[info->
1131 clock_speed_index]
1132 >> 6)
1133 +
1134 4 *
1135 halfcycle_ps(info)
1136 + 2230);
1137 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001138 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001139 (frequency_11(info) * 2) * (28 -
1140 some_delay_2_half_cycles) /
1141 (frequency_11(info) * 2 -
1142 4 * (info->fsb_frequency))) >> 3, 7);
1143 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001144 if (mchbar_read8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001145 some_delay_3_half_cycles = 3;
1146 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001147 mchbar_setbits32(0x220 + (channel << 10), 0x18001117);
1148 mchbar_write32(0x224 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001149 (info->max_slots_used_in_channel - 1) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001150 (info->cas_latency - 5 - info->clock_speed_index)
1151 << 21 | (info->max_slots_used_in_channel +
1152 info->cas_latency - cas_latency_shift - 4) << 16 |
1153 (info->cas_latency - cas_latency_shift - 4) << 26 |
1154 (info->cas_latency - info->clock_speed_index +
Felix Held04be2dd2018-07-29 04:53:22 +02001155 info->max_slots_used_in_channel - 6) << 8);
Angel Ponsdea722b2021-03-26 14:11:12 +01001156 mchbar_write32(0x228 + (channel << 10), info->max_slots_used_in_channel);
1157 mchbar_write8(0x239 + (channel << 10), 32);
1158 mchbar_write32(0x248 + (channel << 10), high_multiplier << 24 |
1159 some_delay_3_half_cycles << 25 | 0x840000);
1160 mchbar_write32(0x278 + (channel << 10), 0xc362042);
1161 mchbar_write32(0x27c + (channel << 10), 0x8b000062);
1162 mchbar_write32(0x24c + (channel << 10),
1163 (!!info->clock_speed_index) << 17 |
1164 ((2 + info->clock_speed_index -
1165 (!!info->clock_speed_index))) << 12 | 0x10200);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001166
Angel Ponsdea722b2021-03-26 14:11:12 +01001167 mchbar_write8(0x267 + (channel << 10), 4);
1168 mchbar_write16(0x272 + (channel << 10), 0x155);
1169 mchbar_clrsetbits32(0x2bc + (channel << 10), 0xffffff, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001170
1171 write_500(info, channel,
1172 ((!info->populated_ranks[channel][1][1])
1173 | (!info->populated_ranks[channel][1][0] << 1)
1174 | (!info->populated_ranks[channel][0][1] << 2)
1175 | (!info->populated_ranks[channel][0][0] << 3)),
1176 0x4c9, 4, 1);
1177 }
1178
Angel Ponsdea722b2021-03-26 14:11:12 +01001179 mchbar_write8(0x2c4, (1 + (info->clock_speed_index != 0)) << 6 | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001180 {
1181 u8 freq_divisor = 2;
1182 if (info->fsb_frequency == frequency_11(info))
1183 freq_divisor = 3;
1184 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1185 freq_divisor = 1;
1186 else
1187 freq_divisor = 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001188 mchbar_write32(0x2c0, freq_divisor << 11 | 0x6009c400);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189 }
1190
1191 if (info->board_lane_delay[3] <= 10) {
1192 if (info->board_lane_delay[3] <= 8)
1193 lane_3_delay = info->board_lane_delay[3];
1194 else
1195 lane_3_delay = 10;
1196 } else {
1197 lane_3_delay = 12;
1198 }
1199 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1200 if (info->clock_speed_index > 1)
1201 cas_latency_derived++;
1202 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001203 mchbar_write32(0x240 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001204 ((info->clock_speed_index == 0) * 0x11000) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001205 0x1002100 | (2 + info->clock_speed_index) << 4 |
1206 (info->cas_latency - 3));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001207 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1208 0x609, 6, 1);
1209 write_500(info, channel,
1210 info->clock_speed_index + 2 * info->cas_latency - 7,
1211 0x601, 6, 1);
1212
Angel Ponsdea722b2021-03-26 14:11:12 +01001213 mchbar_write32(0x250 + (channel << 10),
1214 (lane_3_delay + info->clock_speed_index + 9) << 6 |
1215 info->board_lane_delay[7] << 2 |
1216 info->board_lane_delay[4] << 16 |
1217 info->board_lane_delay[1] << 25 |
1218 info->board_lane_delay[1] << 29 | 1);
1219 mchbar_write32(0x254 + (channel << 10),
1220 info->board_lane_delay[1] >> 3 |
1221 (info->board_lane_delay[8] + 4 * info->use_ecc) << 6 |
1222 0x80 | info->board_lane_delay[6] << 1 |
1223 info->board_lane_delay[2] << 28 |
1224 cas_latency_derived << 16 | 0x4700000);
1225 mchbar_write32(0x258 + (channel << 10),
1226 (info->board_lane_delay[5] + info->clock_speed_index + 9) << 12 |
1227 (info->clock_speed_index - info->cas_latency + 12) << 8 |
1228 info->board_lane_delay[2] << 17 |
1229 info->board_lane_delay[4] << 24 | 0x47);
1230 mchbar_write32(0x25c + (channel << 10),
1231 info->board_lane_delay[1] << 1 |
1232 info->board_lane_delay[0] << 8 | 0x1da50000);
1233 mchbar_write8(0x264 + (channel << 10), 0xff);
1234 mchbar_write8(0x5f8 + (channel << 10), cas_latency_shift << 3 | info->use_ecc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001235 }
1236
1237 program_modules_memory_map(info, 1);
1238
Angel Ponsdea722b2021-03-26 14:11:12 +01001239 mchbar_clrsetbits16(0x610, 0xfe3c,
1240 MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9 | 0x3c);
1241 mchbar_setbits16(0x612, 1 << 8);
1242 mchbar_setbits16(0x214, 0x3e00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001243 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001244 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001245 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001246 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001247 }
1248}
1249
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001250#define DEFAULT_PCI_MMIO_SIZE 2048
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001251
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001252static void program_total_memory_map(struct raminfo *info)
1253{
Angel Pons9333b742020-07-22 16:04:15 +02001254 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001255 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001256 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001257 unsigned int uma_base_igd;
1258 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001259 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 int memory_remap;
1261 unsigned int memory_map[8];
1262 int i;
1263 unsigned int current_limit;
1264 unsigned int tseg_base;
1265 int uma_size_igd = 0, uma_size_gtt = 0;
1266
1267 memset(memory_map, 0, sizeof(memory_map));
1268
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001269 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001270 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001271 gav(t);
1272 const int uma_sizes_gtt[16] =
1273 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1274 /* Igd memory */
1275 const int uma_sizes_igd[16] = {
1276 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1277 256, 512
1278 };
1279
1280 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1281 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1282 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001283
Angel Ponse24f97c2021-04-02 22:42:53 +02001284 mmio_size = DEFAULT_PCI_MMIO_SIZE;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001285
Angel Pons9333b742020-07-22 16:04:15 +02001286 tom = info->total_memory_mb;
1287 if (tom == 4096)
1288 tom = 4032;
1289 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1290 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1291 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001292 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001293 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001295 remap_base = MAX(4096, touud);
1296 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 }
Angel Pons9333b742020-07-22 16:04:15 +02001298 if (touud > 4096)
1299 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001300 quickpath_reserved = 0;
1301
Angel Pons3ab19b32020-07-22 16:29:54 +02001302 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001303
Jacob Garber975a7e32019-06-10 16:32:47 -06001304 gav(t);
1305
1306 if (t & 0x800) {
1307 u32 shift = t >> 20;
1308 if (shift == 0)
1309 die("Quickpath value is 0\n");
1310 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001311 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001312
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001313 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001314 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001315
Angel Pons9333b742020-07-22 16:04:15 +02001316 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001317 uma_base_gtt = uma_base_igd - uma_size_gtt;
1318 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1319 if (!memory_remap)
1320 tseg_base -= quickpath_reserved;
1321 tseg_base = ALIGN_DOWN(tseg_base, 8);
1322
Angel Pons16fe1e02020-07-22 16:12:33 +02001323 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1324 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001325 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001326 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1327 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001328 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001329 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001330
1331 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001332 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1333 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001334 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001335 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001336
1337 current_limit = 0;
1338 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1339 memory_map[1] = 4096;
1340 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001341 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001342 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001343 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1344 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001345 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001346 }
1347}
1348
1349static void collect_system_info(struct raminfo *info)
1350{
1351 u32 capid0[3];
1352 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001353 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001354
Angel Ponsb600d412021-01-16 16:33:48 +01001355 for (i = 0; i < 3; i++) {
1356 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1357 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1358 }
1359 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1360 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1361 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1362
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1364
1365 if ((capid0[1] >> 11) & 1)
1366 info->uma_enabled = 0;
1367 else
1368 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001369 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001370 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1371 info->silicon_revision = 0;
1372
1373 if (capid0[2] & 2) {
1374 info->silicon_revision = 0;
1375 info->max_supported_clock_speed_index = 2;
1376 for (channel = 0; channel < NUM_CHANNELS; channel++)
1377 if (info->populated_ranks[channel][0][0]
1378 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1379 3) {
1380 info->silicon_revision = 2;
1381 info->max_supported_clock_speed_index = 1;
1382 }
1383 } else {
1384 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1385 case 1:
1386 case 2:
1387 info->silicon_revision = 3;
1388 break;
1389 case 3:
1390 info->silicon_revision = 0;
1391 break;
1392 case 0:
1393 info->silicon_revision = 2;
1394 break;
1395 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001396 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001397 case 0x40:
1398 info->silicon_revision = 0;
1399 break;
1400 case 0x48:
1401 info->silicon_revision = 1;
1402 break;
1403 }
1404 }
1405}
1406
1407static void write_training_data(struct raminfo *info)
1408{
1409 int tm, channel, slot, rank, lane;
1410 if (info->revision < 8)
1411 return;
1412
1413 for (tm = 0; tm < 4; tm++)
1414 for (channel = 0; channel < NUM_CHANNELS; channel++)
1415 for (slot = 0; slot < NUM_SLOTS; slot++)
1416 for (rank = 0; rank < NUM_RANKS; rank++)
1417 for (lane = 0; lane < 9; lane++)
1418 write_500(info, channel,
1419 info->
1420 cached_training->
1421 lane_timings[tm]
1422 [channel][slot][rank]
1423 [lane],
1424 get_timing_register_addr
1425 (lane, tm, slot,
1426 rank), 9, 0);
1427 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1428 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1429}
1430
1431static void dump_timings(struct raminfo *info)
1432{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001433 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001434 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001435 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001436 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 slot, rank);
1438 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001439 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001441 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442 read_500(info, channel,
1443 get_timing_register_addr
1444 (lane, i, slot, rank),
1445 9),
1446 info->training.
1447 lane_timings[i][channel][slot][rank]
1448 [lane]);
1449 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001450 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451 }
1452 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001453 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001455 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457}
1458
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001459/* Read timings and other registers that need to be restored verbatim and
1460 put them to CBMEM.
1461 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462static void save_timings(struct raminfo *info)
1463{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465 int channel, slot, rank, lane, i;
1466
1467 train = info->training;
1468 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1469 for (i = 0; i < 4; i++)
1470 train.lane_timings[i][channel][slot][rank][lane] =
1471 read_500(info, channel,
1472 get_timing_register_addr(lane, i, slot,
1473 rank), 9);
1474 train.reg_178 = read_1d0(0x178, 7);
1475 train.reg_10b = read_1d0(0x10b, 6);
1476
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001477 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1478 u32 reg32;
Angel Ponsdea722b2021-03-26 14:11:12 +01001479 reg32 = mchbar_read32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001480 train.reg274265[channel][0] = reg32 >> 16;
1481 train.reg274265[channel][1] = reg32 & 0xffff;
Angel Ponsdea722b2021-03-26 14:11:12 +01001482 train.reg274265[channel][2] = mchbar_read16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001483 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001484 train.reg2ca9_bit0 = mchbar_read8(0x2ca9) & 1;
1485 train.reg_6dc = mchbar_read32(0x6dc);
1486 train.reg_6e8 = mchbar_read32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001487
Arthur Heymansb3282092019-04-14 17:53:28 +02001488 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1489 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001490
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001491 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001492 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1493 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494}
1495
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001496static const struct ram_training *get_cached_training(void)
1497{
Shelley Chenad9cd682020-07-23 16:10:52 -07001498 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1499 MRC_CACHE_VERSION,
1500 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001501}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001502
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001503static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1504{
1505 int ranks_in_channel;
1506 ranks_in_channel = info->populated_ranks[channel][0][0]
1507 + info->populated_ranks[channel][0][1]
1508 + info->populated_ranks[channel][1][0]
1509 + info->populated_ranks[channel][1][1];
1510
1511 /* empty channel */
1512 if (ranks_in_channel == 0)
1513 return 1;
1514
1515 if (ranks_in_channel != ranks)
1516 return 0;
1517 /* single slot */
1518 if (info->populated_ranks[channel][0][0] !=
1519 info->populated_ranks[channel][1][0])
1520 return 1;
1521 if (info->populated_ranks[channel][0][1] !=
1522 info->populated_ranks[channel][1][1])
1523 return 1;
1524 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1525 return 0;
1526 if (info->density[channel][0] != info->density[channel][1])
1527 return 0;
1528 return 1;
1529}
1530
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001531static void read_4090(struct raminfo *info)
1532{
1533 int i, channel, slot, rank, lane;
1534 for (i = 0; i < 2; i++)
1535 for (slot = 0; slot < NUM_SLOTS; slot++)
1536 for (rank = 0; rank < NUM_RANKS; rank++)
1537 for (lane = 0; lane < 9; lane++)
1538 info->training.
1539 lane_timings[0][i][slot][rank][lane]
1540 = 32;
1541
1542 for (i = 1; i < 4; i++)
1543 for (channel = 0; channel < NUM_CHANNELS; channel++)
1544 for (slot = 0; slot < NUM_SLOTS; slot++)
1545 for (rank = 0; rank < NUM_RANKS; rank++)
1546 for (lane = 0; lane < 9; lane++) {
1547 info->training.
1548 lane_timings[i][channel]
1549 [slot][rank][lane] =
1550 read_500(info, channel,
1551 get_timing_register_addr
1552 (lane, i, slot,
1553 rank), 9)
1554 + (i == 1) * 11; // !!!!
1555 }
1556
1557}
1558
1559static u32 get_etalon2(int flip, u32 addr)
1560{
1561 const u16 invmask[] = {
1562 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1563 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1564 };
1565 u32 ret;
1566 u32 comp4 = addr / 480;
1567 addr %= 480;
1568 u32 comp1 = addr & 0xf;
1569 u32 comp2 = (addr >> 4) & 1;
1570 u32 comp3 = addr >> 5;
1571
1572 if (comp4)
1573 ret = 0x1010101 << (comp4 - 1);
1574 else
1575 ret = 0;
1576 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1577 ret = ~ret;
1578
1579 return ret;
1580}
1581
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001582static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583{
1584 msr_t msr = {.lo = 0, .hi = 0 };
1585
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001586 wrmsr(MTRR_PHYS_BASE(3), msr);
1587 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588}
1589
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001590static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001591{
1592 msr_t msr;
1593 msr.lo = base | MTRR_TYPE_WRPROT;
1594 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001595 wrmsr(MTRR_PHYS_BASE(3), msr);
1596 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597 & 0xffffffff);
1598 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001599 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600}
1601
1602static void flush_cache(u32 start, u32 size)
1603{
1604 u32 end;
1605 u32 addr;
1606
1607 end = start + (ALIGN_DOWN(size + 4096, 4096));
1608 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001609 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610}
1611
1612static void clear_errors(void)
1613{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001614 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001615}
1616
1617static void write_testing(struct raminfo *info, int totalrank, int flip)
1618{
1619 int nwrites = 0;
1620 /* in 8-byte units. */
1621 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001622 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001623
Patrick Rudolph819c2062019-11-29 19:27:37 +01001624 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001625 for (offset = 0; offset < 9 * 480; offset += 2) {
1626 write32(base + offset * 8, get_etalon2(flip, offset));
1627 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1628 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1629 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1630 nwrites += 4;
1631 if (nwrites >= 320) {
1632 clear_errors();
1633 nwrites = 0;
1634 }
1635 }
1636}
1637
1638static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1639{
1640 u8 failmask = 0;
1641 int i;
1642 int comp1, comp2, comp3;
1643 u32 failxor[2] = { 0, 0 };
1644
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001645 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646
1647 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1648 for (comp1 = 0; comp1 < 4; comp1++)
1649 for (comp2 = 0; comp2 < 60; comp2++) {
1650 u32 re[4];
1651 u32 curroffset =
1652 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1653 read128((total_rank << 28) | (curroffset << 3),
1654 (u64 *) re);
1655 failxor[0] |=
1656 get_etalon2(flip, curroffset) ^ re[0];
1657 failxor[1] |=
1658 get_etalon2(flip, curroffset) ^ re[1];
1659 failxor[0] |=
1660 get_etalon2(flip, curroffset | 1) ^ re[2];
1661 failxor[1] |=
1662 get_etalon2(flip, curroffset | 1) ^ re[3];
1663 }
1664 for (i = 0; i < 8; i++)
1665 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1666 failmask |= 1 << i;
1667 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001668 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669 flush_cache((total_rank << 28), 1728 * 5 * 4);
1670 return failmask;
1671}
1672
1673const u32 seed1[0x18] = {
1674 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1675 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1676 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1677 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1678 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1679 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1680};
1681
1682static u32 get_seed2(int a, int b)
1683{
1684 const u32 seed2[5] = {
1685 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1686 0x5b6db6db,
1687 };
1688 u32 r;
1689 r = seed2[(a + (a >= 10)) / 5];
1690 return b ? ~r : r;
1691}
1692
1693static int make_shift(int comp2, int comp5, int x)
1694{
1695 const u8 seed3[32] = {
1696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1697 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1698 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1699 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1700 };
1701
1702 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1703}
1704
1705static u32 get_etalon(int flip, u32 addr)
1706{
1707 u32 mask_byte = 0;
1708 int comp1 = (addr >> 1) & 1;
1709 int comp2 = (addr >> 3) & 0x1f;
1710 int comp3 = (addr >> 8) & 0xf;
1711 int comp4 = (addr >> 12) & 0xf;
1712 int comp5 = (addr >> 16) & 0x1f;
1713 u32 mask_bit = ~(0x10001 << comp3);
1714 u32 part1;
1715 u32 part2;
1716 int byte;
1717
1718 part2 =
1719 ((seed1[comp5] >>
1720 make_shift(comp2, comp5,
1721 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1722 part1 =
1723 ((seed1[comp5] >>
1724 make_shift(comp2, comp5,
1725 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1726
1727 for (byte = 0; byte < 4; byte++)
1728 if ((get_seed2(comp5, comp4) >>
1729 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1730 mask_byte |= 0xff << (8 * byte);
1731
1732 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1733 (comp3 + 16));
1734}
1735
1736static void
1737write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1738 char flip)
1739{
1740 int i;
1741 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001742 write32p((totalrank << 28) | (region << 25) | (block << 16) |
1743 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001744}
1745
1746static u8
1747check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1748 char flip)
1749{
1750 u8 failmask = 0;
1751 u32 failxor[2];
1752 int i;
1753 int comp1, comp2, comp3;
1754
1755 failxor[0] = 0;
1756 failxor[1] = 0;
1757
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001758 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
1760 for (comp1 = 0; comp1 < 16; comp1++)
1761 for (comp2 = 0; comp2 < 64; comp2++) {
1762 u32 addr =
1763 (totalrank << 28) | (region << 25) | (block
1764 << 16)
1765 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
1766 2);
1767 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001768 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001769 }
1770 for (i = 0; i < 8; i++)
1771 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1772 failmask |= 1 << i;
1773 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001774 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001775 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
1776 return failmask;
1777}
1778
1779static int check_bounded(unsigned short *vals, u16 bound)
1780{
1781 int i;
1782
1783 for (i = 0; i < 8; i++)
1784 if (vals[i] < bound)
1785 return 0;
1786 return 1;
1787}
1788
1789enum state {
1790 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
1791};
1792
1793static int validate_state(enum state *in)
1794{
1795 int i;
1796 for (i = 0; i < 8; i++)
1797 if (in[i] != COMPLETE)
1798 return 0;
1799 return 1;
1800}
1801
1802static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001803do_fsm(enum state *state, u16 *counter,
1804 u8 fail_mask, int margin, int uplimit,
1805 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806{
1807 int lane;
1808
1809 for (lane = 0; lane < 8; lane++) {
1810 int is_fail = (fail_mask >> lane) & 1;
1811 switch (state[lane]) {
1812 case BEFORE_USABLE:
1813 if (!is_fail) {
1814 counter[lane] = 1;
1815 state[lane] = AT_USABLE;
1816 break;
1817 }
1818 counter[lane] = 0;
1819 state[lane] = BEFORE_USABLE;
1820 break;
1821 case AT_USABLE:
1822 if (!is_fail) {
1823 ++counter[lane];
1824 if (counter[lane] >= margin) {
1825 state[lane] = AT_MARGIN;
1826 res_low[lane] = val - margin + 1;
1827 break;
1828 }
1829 state[lane] = 1;
1830 break;
1831 }
1832 counter[lane] = 0;
1833 state[lane] = BEFORE_USABLE;
1834 break;
1835 case AT_MARGIN:
1836 if (is_fail) {
1837 state[lane] = COMPLETE;
1838 res_high[lane] = val - 1;
1839 } else {
1840 counter[lane]++;
1841 state[lane] = AT_MARGIN;
1842 if (val == uplimit) {
1843 state[lane] = COMPLETE;
1844 res_high[lane] = uplimit;
1845 }
1846 }
1847 break;
1848 case COMPLETE:
1849 break;
1850 }
1851 }
1852}
1853
1854static void
1855train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
1856 u8 total_rank, u8 reg_178, int first_run, int niter,
1857 timing_bounds_t * timings)
1858{
1859 int lane;
1860 enum state state[8];
1861 u16 count[8];
1862 u8 lower_usable[8];
1863 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02001864 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02001866 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001867
Elyes HAOUAS019a2532019-05-25 11:13:43 +02001868 for (i = 0; i < 8; i++)
1869 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001870
1871 if (!first_run) {
1872 int is_all_ok = 1;
1873 for (lane = 0; lane < 8; lane++)
1874 if (timings[reg_178][channel][slot][rank][lane].
1875 smallest ==
1876 timings[reg_178][channel][slot][rank][lane].
1877 largest) {
1878 timings[reg_178][channel][slot][rank][lane].
1879 smallest = 0;
1880 timings[reg_178][channel][slot][rank][lane].
1881 largest = 0;
1882 is_all_ok = 0;
1883 }
1884 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001885 for (i = 0; i < 8; i++)
1886 state[i] = COMPLETE;
1887 }
1888 }
1889
1890 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
1891 u8 failmask = 0;
1892 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
1893 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
1894 failmask = check_testing(info, total_rank, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01001895 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001896 do_fsm(state, count, failmask, 5, 47, lower_usable,
1897 upper_usable, reg1b3);
1898 }
1899
1900 if (reg1b3) {
1901 write_1d0(0, 0x1b3, 6, 1);
1902 write_1d0(0, 0x1a3, 6, 1);
1903 for (lane = 0; lane < 8; lane++) {
1904 if (state[lane] == COMPLETE) {
1905 timings[reg_178][channel][slot][rank][lane].
1906 smallest =
1907 lower_usable[lane] +
1908 (info->training.
1909 lane_timings[0][channel][slot][rank][lane]
1910 & 0x3F) - 32;
1911 timings[reg_178][channel][slot][rank][lane].
1912 largest =
1913 upper_usable[lane] +
1914 (info->training.
1915 lane_timings[0][channel][slot][rank][lane]
1916 & 0x3F) - 32;
1917 }
1918 }
1919 }
1920
1921 if (!first_run) {
1922 for (lane = 0; lane < 8; lane++)
1923 if (state[lane] == COMPLETE) {
1924 write_500(info, channel,
1925 timings[reg_178][channel][slot][rank]
1926 [lane].smallest,
1927 get_timing_register_addr(lane, 0,
1928 slot, rank),
1929 9, 1);
1930 write_500(info, channel,
1931 timings[reg_178][channel][slot][rank]
1932 [lane].smallest +
1933 info->training.
1934 lane_timings[1][channel][slot][rank]
1935 [lane]
1936 -
1937 info->training.
1938 lane_timings[0][channel][slot][rank]
1939 [lane], get_timing_register_addr(lane,
1940 1,
1941 slot,
1942 rank),
1943 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02001944 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945 } else
Felix Held04be2dd2018-07-29 04:53:22 +02001946 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001947
1948 do {
1949 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001950 for (i = 0; i < niter; i++) {
1951 if (failmask == 0xFF)
1952 break;
1953 failmask |=
1954 check_testing_type2(info, total_rank, 2, i,
1955 0);
1956 failmask |=
1957 check_testing_type2(info, total_rank, 3, i,
1958 1);
1959 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001960 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001961 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02001962 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001963 if ((1 << lane) & failmask) {
1964 if (timings[reg_178][channel]
1965 [slot][rank][lane].
1966 largest <=
1967 timings[reg_178][channel]
1968 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02001969 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970 [lane] = -1;
1971 else {
Felix Held04be2dd2018-07-29 04:53:22 +02001972 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001973 [lane] = 0;
1974 timings[reg_178]
1975 [channel][slot]
1976 [rank][lane].
1977 smallest++;
1978 write_500(info, channel,
1979 timings
1980 [reg_178]
1981 [channel]
1982 [slot][rank]
1983 [lane].
1984 smallest,
1985 get_timing_register_addr
1986 (lane, 0,
1987 slot, rank),
1988 9, 1);
1989 write_500(info, channel,
1990 timings
1991 [reg_178]
1992 [channel]
1993 [slot][rank]
1994 [lane].
1995 smallest +
1996 info->
1997 training.
1998 lane_timings
1999 [1][channel]
2000 [slot][rank]
2001 [lane]
2002 -
2003 info->
2004 training.
2005 lane_timings
2006 [0][channel]
2007 [slot][rank]
2008 [lane],
2009 get_timing_register_addr
2010 (lane, 1,
2011 slot, rank),
2012 9, 1);
2013 }
2014 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002015 num_successfully_checked[lane]
2016 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002017 }
2018 }
Felix Held04be2dd2018-07-29 04:53:22 +02002019 while (!check_bounded(num_successfully_checked, 2))
2020 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002021
2022 for (lane = 0; lane < 8; lane++)
2023 if (state[lane] == COMPLETE) {
2024 write_500(info, channel,
2025 timings[reg_178][channel][slot][rank]
2026 [lane].largest,
2027 get_timing_register_addr(lane, 0,
2028 slot, rank),
2029 9, 1);
2030 write_500(info, channel,
2031 timings[reg_178][channel][slot][rank]
2032 [lane].largest +
2033 info->training.
2034 lane_timings[1][channel][slot][rank]
2035 [lane]
2036 -
2037 info->training.
2038 lane_timings[0][channel][slot][rank]
2039 [lane], get_timing_register_addr(lane,
2040 1,
2041 slot,
2042 rank),
2043 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002044 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002045 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002046 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002047
2048 do {
2049 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002050 for (i = 0; i < niter; i++) {
2051 if (failmask == 0xFF)
2052 break;
2053 failmask |=
2054 check_testing_type2(info, total_rank, 2, i,
2055 0);
2056 failmask |=
2057 check_testing_type2(info, total_rank, 3, i,
2058 1);
2059 }
2060
Angel Ponsdea722b2021-03-26 14:11:12 +01002061 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002062 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002063 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002064 if ((1 << lane) & failmask) {
2065 if (timings[reg_178][channel]
2066 [slot][rank][lane].
2067 largest <=
2068 timings[reg_178][channel]
2069 [slot][rank][lane].
2070 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002071 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002072 [lane] = -1;
2073 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002074 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002075 [lane] = 0;
2076 timings[reg_178]
2077 [channel][slot]
2078 [rank][lane].
2079 largest--;
2080 write_500(info, channel,
2081 timings
2082 [reg_178]
2083 [channel]
2084 [slot][rank]
2085 [lane].
2086 largest,
2087 get_timing_register_addr
2088 (lane, 0,
2089 slot, rank),
2090 9, 1);
2091 write_500(info, channel,
2092 timings
2093 [reg_178]
2094 [channel]
2095 [slot][rank]
2096 [lane].
2097 largest +
2098 info->
2099 training.
2100 lane_timings
2101 [1][channel]
2102 [slot][rank]
2103 [lane]
2104 -
2105 info->
2106 training.
2107 lane_timings
2108 [0][channel]
2109 [slot][rank]
2110 [lane],
2111 get_timing_register_addr
2112 (lane, 1,
2113 slot, rank),
2114 9, 1);
2115 }
2116 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002117 num_successfully_checked[lane]
2118 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002119 }
2120 }
2121 }
Felix Held04be2dd2018-07-29 04:53:22 +02002122 while (!check_bounded(num_successfully_checked, 3))
2123 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002124
2125 for (lane = 0; lane < 8; lane++) {
2126 write_500(info, channel,
2127 info->training.
2128 lane_timings[0][channel][slot][rank][lane],
2129 get_timing_register_addr(lane, 0, slot, rank),
2130 9, 1);
2131 write_500(info, channel,
2132 info->training.
2133 lane_timings[1][channel][slot][rank][lane],
2134 get_timing_register_addr(lane, 1, slot, rank),
2135 9, 1);
2136 if (timings[reg_178][channel][slot][rank][lane].
2137 largest <=
2138 timings[reg_178][channel][slot][rank][lane].
2139 smallest) {
2140 timings[reg_178][channel][slot][rank][lane].
2141 largest = 0;
2142 timings[reg_178][channel][slot][rank][lane].
2143 smallest = 0;
2144 }
2145 }
2146 }
2147}
2148
2149static void set_10b(struct raminfo *info, u8 val)
2150{
2151 int channel;
2152 int slot, rank;
2153 int lane;
2154
2155 if (read_1d0(0x10b, 6) == val)
2156 return;
2157
2158 write_1d0(val, 0x10b, 6, 1);
2159
2160 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2161 u16 reg_500;
2162 reg_500 = read_500(info, channel,
2163 get_timing_register_addr(lane, 0, slot,
2164 rank), 9);
2165 if (val == 1) {
2166 if (lut16[info->clock_speed_index] <= reg_500)
2167 reg_500 -= lut16[info->clock_speed_index];
2168 else
2169 reg_500 = 0;
2170 } else {
2171 reg_500 += lut16[info->clock_speed_index];
2172 }
2173 write_500(info, channel, reg_500,
2174 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2175 }
2176}
2177
2178static void set_ecc(int onoff)
2179{
2180 int channel;
2181 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2182 u8 t;
Angel Ponsdea722b2021-03-26 14:11:12 +01002183 t = mchbar_read8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002184 if (onoff)
2185 t |= 1;
2186 else
2187 t &= ~1;
Angel Ponsdea722b2021-03-26 14:11:12 +01002188 mchbar_write8((channel << 10) + 0x5f8, t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002189 }
2190}
2191
2192static void set_178(u8 val)
2193{
2194 if (val >= 31)
2195 val = val - 31;
2196 else
2197 val = 63 - val;
2198
2199 write_1d0(2 * val, 0x178, 7, 1);
2200}
2201
2202static void
2203write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2204 int type)
2205{
2206 int lane;
2207
2208 for (lane = 0; lane < 8; lane++)
2209 write_500(info, channel,
2210 info->training.
2211 lane_timings[type][channel][slot][rank][lane],
2212 get_timing_register_addr(lane, type, slot, rank), 9,
2213 0);
2214}
2215
2216static void
2217try_timing_offsets(struct raminfo *info, int channel,
2218 int slot, int rank, int totalrank)
2219{
2220 u16 count[8];
2221 enum state state[8];
2222 u8 lower_usable[8], upper_usable[8];
2223 int lane;
2224 int i;
2225 int flip = 1;
2226 int timing_offset;
2227
2228 for (i = 0; i < 8; i++)
2229 state[i] = BEFORE_USABLE;
2230
2231 memset(count, 0, sizeof(count));
2232
2233 for (lane = 0; lane < 8; lane++)
2234 write_500(info, channel,
2235 info->training.
2236 lane_timings[2][channel][slot][rank][lane] + 32,
2237 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2238
2239 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2240 timing_offset++) {
2241 u8 failmask;
2242 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2243 failmask = 0;
2244 for (i = 0; i < 2 && failmask != 0xff; i++) {
2245 flip = !flip;
2246 write_testing(info, totalrank, flip);
2247 failmask |= check_testing(info, totalrank, flip);
2248 }
2249 do_fsm(state, count, failmask, 10, 63, lower_usable,
2250 upper_usable, timing_offset);
2251 }
2252 write_1d0(0, 0x1bb, 6, 1);
2253 dump_timings(info);
2254 if (!validate_state(state))
2255 die("Couldn't discover DRAM timings (1)\n");
2256
2257 for (lane = 0; lane < 8; lane++) {
2258 u8 bias = 0;
2259
2260 if (info->silicon_revision) {
2261 int usable_length;
2262
2263 usable_length = upper_usable[lane] - lower_usable[lane];
2264 if (usable_length >= 20) {
2265 bias = usable_length / 2 - 10;
2266 if (bias >= 2)
2267 bias = 2;
2268 }
2269 }
2270 write_500(info, channel,
2271 info->training.
2272 lane_timings[2][channel][slot][rank][lane] +
2273 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2274 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2275 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2276 info->training.lane_timings[2][channel][slot][rank][lane] +
2277 lower_usable[lane];
2278 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2279 info->training.lane_timings[2][channel][slot][rank][lane] +
2280 upper_usable[lane];
2281 info->training.timing2_offset[channel][slot][rank][lane] =
2282 info->training.lane_timings[2][channel][slot][rank][lane];
2283 }
2284}
2285
2286static u8
2287choose_training(struct raminfo *info, int channel, int slot, int rank,
2288 int lane, timing_bounds_t * timings, u8 center_178)
2289{
2290 u16 central_weight;
2291 u16 side_weight;
2292 unsigned int sum = 0, count = 0;
2293 u8 span;
2294 u8 lower_margin, upper_margin;
2295 u8 reg_178;
2296 u8 result;
2297
2298 span = 12;
2299 central_weight = 20;
2300 side_weight = 20;
2301 if (info->silicon_revision == 1 && channel == 1) {
2302 central_weight = 5;
2303 side_weight = 20;
2304 if ((info->
2305 populated_ranks_mask[1] ^ (info->
2306 populated_ranks_mask[1] >> 2)) &
2307 1)
2308 span = 18;
2309 }
2310 if ((info->populated_ranks_mask[0] & 5) == 5) {
2311 central_weight = 20;
2312 side_weight = 20;
2313 }
2314 if (info->clock_speed_index >= 2
2315 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2316 if (info->silicon_revision == 1) {
2317 switch (channel) {
2318 case 0:
2319 if (lane == 1) {
2320 central_weight = 10;
2321 side_weight = 20;
2322 }
2323 break;
2324 case 1:
2325 if (lane == 6) {
2326 side_weight = 5;
2327 central_weight = 20;
2328 }
2329 break;
2330 }
2331 }
2332 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2333 side_weight = 5;
2334 central_weight = 20;
2335 }
2336 }
2337 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2338 reg_178 += span) {
2339 u8 smallest;
2340 u8 largest;
2341 largest = timings[reg_178][channel][slot][rank][lane].largest;
2342 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2343 if (largest - smallest + 1 >= 5) {
2344 unsigned int weight;
2345 if (reg_178 == center_178)
2346 weight = central_weight;
2347 else
2348 weight = side_weight;
2349 sum += weight * (largest + smallest);
2350 count += weight;
2351 }
2352 }
2353 dump_timings(info);
2354 if (count == 0)
2355 die("Couldn't discover DRAM timings (2)\n");
2356 result = sum / (2 * count);
2357 lower_margin =
2358 result - timings[center_178][channel][slot][rank][lane].smallest;
2359 upper_margin =
2360 timings[center_178][channel][slot][rank][lane].largest - result;
2361 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002362 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002364 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002365 return result;
2366}
2367
2368#define STANDARD_MIN_MARGIN 5
2369
2370static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2371{
2372 u16 margin[64];
2373 int lane, rank, slot, channel;
2374 u8 reg178;
2375 int count = 0, sum = 0;
2376
2377 for (reg178 = reg178_min[info->clock_speed_index];
2378 reg178 < reg178_max[info->clock_speed_index];
2379 reg178 += reg178_step[info->clock_speed_index]) {
2380 margin[reg178] = -1;
2381 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2382 int curmargin =
2383 timings[reg178][channel][slot][rank][lane].largest -
2384 timings[reg178][channel][slot][rank][lane].
2385 smallest + 1;
2386 if (curmargin < margin[reg178])
2387 margin[reg178] = curmargin;
2388 }
2389 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2390 u16 weight;
2391 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2392 sum += weight * reg178;
2393 count += weight;
2394 }
2395 }
2396 dump_timings(info);
2397 if (count == 0)
2398 die("Couldn't discover DRAM timings (3)\n");
2399
2400 u8 threshold;
2401
2402 for (threshold = 30; threshold >= 5; threshold--) {
2403 int usable_length = 0;
2404 int smallest_fount = 0;
2405 for (reg178 = reg178_min[info->clock_speed_index];
2406 reg178 < reg178_max[info->clock_speed_index];
2407 reg178 += reg178_step[info->clock_speed_index])
2408 if (margin[reg178] >= threshold) {
2409 usable_length +=
2410 reg178_step[info->clock_speed_index];
2411 info->training.reg178_largest =
2412 reg178 -
2413 2 * reg178_step[info->clock_speed_index];
2414
2415 if (!smallest_fount) {
2416 smallest_fount = 1;
2417 info->training.reg178_smallest =
2418 reg178 +
2419 reg178_step[info->
2420 clock_speed_index];
2421 }
2422 }
2423 if (usable_length >= 0x21)
2424 break;
2425 }
2426
2427 return sum / count;
2428}
2429
2430static int check_cached_sanity(struct raminfo *info)
2431{
2432 int lane;
2433 int slot, rank;
2434 int channel;
2435
2436 if (!info->cached_training)
2437 return 0;
2438
2439 for (channel = 0; channel < NUM_CHANNELS; channel++)
2440 for (slot = 0; slot < NUM_SLOTS; slot++)
2441 for (rank = 0; rank < NUM_RANKS; rank++)
2442 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2443 u16 cached_value, estimation_value;
2444 cached_value =
2445 info->cached_training->
2446 lane_timings[1][channel][slot][rank]
2447 [lane];
2448 if (cached_value >= 0x18
2449 && cached_value <= 0x1E7) {
2450 estimation_value =
2451 info->training.
2452 lane_timings[1][channel]
2453 [slot][rank][lane];
2454 if (estimation_value <
2455 cached_value - 24)
2456 return 0;
2457 if (estimation_value >
2458 cached_value + 24)
2459 return 0;
2460 }
2461 }
2462 return 1;
2463}
2464
2465static int try_cached_training(struct raminfo *info)
2466{
2467 u8 saved_243[2];
2468 u8 tm;
2469
2470 int channel, slot, rank, lane;
2471 int flip = 1;
2472 int i, j;
2473
2474 if (!check_cached_sanity(info))
2475 return 0;
2476
2477 info->training.reg178_center = info->cached_training->reg178_center;
2478 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2479 info->training.reg178_largest = info->cached_training->reg178_largest;
2480 memcpy(&info->training.timing_bounds,
2481 &info->cached_training->timing_bounds,
2482 sizeof(info->training.timing_bounds));
2483 memcpy(&info->training.timing_offset,
2484 &info->cached_training->timing_offset,
2485 sizeof(info->training.timing_offset));
2486
2487 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002488 saved_243[0] = mchbar_read8(0x243);
2489 saved_243[1] = mchbar_read8(0x643);
2490 mchbar_write8(0x243, saved_243[0] | 2);
2491 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002492 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002493 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002494 if (read_1d0(0x10b, 6) & 1)
2495 set_10b(info, 0);
2496 for (tm = 0; tm < 2; tm++) {
2497 int totalrank;
2498
2499 set_178(tm ? info->cached_training->reg178_largest : info->
2500 cached_training->reg178_smallest);
2501
2502 totalrank = 0;
2503 /* Check timing ranges. With i == 0 we check smallest one and with
2504 i == 1 the largest bound. With j == 0 we check that on the bound
2505 it still works whereas with j == 1 we check that just outside of
2506 bound we fail.
2507 */
2508 FOR_POPULATED_RANKS_BACKWARDS {
2509 for (i = 0; i < 2; i++) {
2510 for (lane = 0; lane < 8; lane++) {
2511 write_500(info, channel,
2512 info->cached_training->
2513 timing2_bounds[channel][slot]
2514 [rank][lane][i],
2515 get_timing_register_addr(lane,
2516 3,
2517 slot,
2518 rank),
2519 9, 1);
2520
2521 if (!i)
2522 write_500(info, channel,
2523 info->
2524 cached_training->
2525 timing2_offset
2526 [channel][slot][rank]
2527 [lane],
2528 get_timing_register_addr
2529 (lane, 2, slot, rank),
2530 9, 1);
2531 write_500(info, channel,
2532 i ? info->cached_training->
2533 timing_bounds[tm][channel]
2534 [slot][rank][lane].
2535 largest : info->
2536 cached_training->
2537 timing_bounds[tm][channel]
2538 [slot][rank][lane].smallest,
2539 get_timing_register_addr(lane,
2540 0,
2541 slot,
2542 rank),
2543 9, 1);
2544 write_500(info, channel,
2545 info->cached_training->
2546 timing_offset[channel][slot]
2547 [rank][lane] +
2548 (i ? info->cached_training->
2549 timing_bounds[tm][channel]
2550 [slot][rank][lane].
2551 largest : info->
2552 cached_training->
2553 timing_bounds[tm][channel]
2554 [slot][rank][lane].
2555 smallest) - 64,
2556 get_timing_register_addr(lane,
2557 1,
2558 slot,
2559 rank),
2560 9, 1);
2561 }
2562 for (j = 0; j < 2; j++) {
2563 u8 failmask;
2564 u8 expected_failmask;
2565 char reg1b3;
2566
2567 reg1b3 = (j == 1) + 4;
2568 reg1b3 =
2569 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2570 write_1d0(reg1b3, 0x1bb, 6, 1);
2571 write_1d0(reg1b3, 0x1b3, 6, 1);
2572 write_1d0(reg1b3, 0x1a3, 6, 1);
2573
2574 flip = !flip;
2575 write_testing(info, totalrank, flip);
2576 failmask =
2577 check_testing(info, totalrank,
2578 flip);
2579 expected_failmask =
2580 j == 0 ? 0x00 : 0xff;
2581 if (failmask != expected_failmask)
2582 goto fail;
2583 }
2584 }
2585 totalrank++;
2586 }
2587 }
2588
2589 set_178(info->cached_training->reg178_center);
2590 if (info->use_ecc)
2591 set_ecc(1);
2592 write_training_data(info);
2593 write_1d0(0, 322, 3, 1);
2594 info->training = *info->cached_training;
2595
2596 write_1d0(0, 0x1bb, 6, 1);
2597 write_1d0(0, 0x1b3, 6, 1);
2598 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002599 mchbar_write8(0x243, saved_243[0]);
2600 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002601
2602 return 1;
2603
2604fail:
2605 FOR_POPULATED_RANKS {
2606 write_500_timings_type(info, channel, slot, rank, 1);
2607 write_500_timings_type(info, channel, slot, rank, 2);
2608 write_500_timings_type(info, channel, slot, rank, 3);
2609 }
2610
2611 write_1d0(0, 0x1bb, 6, 1);
2612 write_1d0(0, 0x1b3, 6, 1);
2613 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002614 mchbar_write8(0x243, saved_243[0]);
2615 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002616
2617 return 0;
2618}
2619
2620static void do_ram_training(struct raminfo *info)
2621{
2622 u8 saved_243[2];
2623 int totalrank = 0;
2624 u8 reg_178;
2625 int niter;
2626
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002627 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002628 int lane, rank, slot, channel;
2629 u8 reg178_center;
2630
2631 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002632 saved_243[0] = mchbar_read8(0x243);
2633 saved_243[1] = mchbar_read8(0x643);
2634 mchbar_write8(0x243, saved_243[0] | 2);
2635 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002636 switch (info->clock_speed_index) {
2637 case 0:
2638 niter = 5;
2639 break;
2640 case 1:
2641 niter = 10;
2642 break;
2643 default:
2644 niter = 19;
2645 break;
2646 }
2647 set_ecc(0);
2648
2649 FOR_POPULATED_RANKS_BACKWARDS {
2650 int i;
2651
2652 write_500_timings_type(info, channel, slot, rank, 0);
2653
2654 write_testing(info, totalrank, 0);
2655 for (i = 0; i < niter; i++) {
2656 write_testing_type2(info, totalrank, 2, i, 0);
2657 write_testing_type2(info, totalrank, 3, i, 1);
2658 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002659 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002660 totalrank++;
2661 }
2662
2663 if (reg178_min[info->clock_speed_index] <
2664 reg178_max[info->clock_speed_index])
2665 memset(timings[reg178_min[info->clock_speed_index]], 0,
2666 sizeof(timings[0]) *
2667 (reg178_max[info->clock_speed_index] -
2668 reg178_min[info->clock_speed_index]));
2669 for (reg_178 = reg178_min[info->clock_speed_index];
2670 reg_178 < reg178_max[info->clock_speed_index];
2671 reg_178 += reg178_step[info->clock_speed_index]) {
2672 totalrank = 0;
2673 set_178(reg_178);
2674 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2675 for (slot = 0; slot < NUM_SLOTS; slot++)
2676 for (rank = 0; rank < NUM_RANKS; rank++) {
2677 memset(&timings[reg_178][channel][slot]
2678 [rank][0].smallest, 0, 16);
2679 if (info->
2680 populated_ranks[channel][slot]
2681 [rank]) {
2682 train_ram_at_178(info, channel,
2683 slot, rank,
2684 totalrank,
2685 reg_178, 1,
2686 niter,
2687 timings);
2688 totalrank++;
2689 }
2690 }
2691 }
2692
2693 reg178_center = choose_reg178(info, timings);
2694
2695 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2696 info->training.timing_bounds[0][channel][slot][rank][lane].
2697 smallest =
2698 timings[info->training.
2699 reg178_smallest][channel][slot][rank][lane].
2700 smallest;
2701 info->training.timing_bounds[0][channel][slot][rank][lane].
2702 largest =
2703 timings[info->training.
2704 reg178_smallest][channel][slot][rank][lane].largest;
2705 info->training.timing_bounds[1][channel][slot][rank][lane].
2706 smallest =
2707 timings[info->training.
2708 reg178_largest][channel][slot][rank][lane].smallest;
2709 info->training.timing_bounds[1][channel][slot][rank][lane].
2710 largest =
2711 timings[info->training.
2712 reg178_largest][channel][slot][rank][lane].largest;
2713 info->training.timing_offset[channel][slot][rank][lane] =
2714 info->training.lane_timings[1][channel][slot][rank][lane]
2715 -
2716 info->training.lane_timings[0][channel][slot][rank][lane] +
2717 64;
2718 }
2719
2720 if (info->silicon_revision == 1
2721 && (info->
2722 populated_ranks_mask[1] ^ (info->
2723 populated_ranks_mask[1] >> 2)) & 1) {
2724 int ranks_after_channel1;
2725
2726 totalrank = 0;
2727 for (reg_178 = reg178_center - 18;
2728 reg_178 <= reg178_center + 18; reg_178 += 18) {
2729 totalrank = 0;
2730 set_178(reg_178);
2731 for (slot = 0; slot < NUM_SLOTS; slot++)
2732 for (rank = 0; rank < NUM_RANKS; rank++) {
2733 if (info->
2734 populated_ranks[1][slot][rank]) {
2735 train_ram_at_178(info, 1, slot,
2736 rank,
2737 totalrank,
2738 reg_178, 0,
2739 niter,
2740 timings);
2741 totalrank++;
2742 }
2743 }
2744 }
2745 ranks_after_channel1 = totalrank;
2746
2747 for (reg_178 = reg178_center - 12;
2748 reg_178 <= reg178_center + 12; reg_178 += 12) {
2749 totalrank = ranks_after_channel1;
2750 set_178(reg_178);
2751 for (slot = 0; slot < NUM_SLOTS; slot++)
2752 for (rank = 0; rank < NUM_RANKS; rank++)
2753 if (info->
2754 populated_ranks[0][slot][rank]) {
2755 train_ram_at_178(info, 0, slot,
2756 rank,
2757 totalrank,
2758 reg_178, 0,
2759 niter,
2760 timings);
2761 totalrank++;
2762 }
2763
2764 }
2765 } else {
2766 for (reg_178 = reg178_center - 12;
2767 reg_178 <= reg178_center + 12; reg_178 += 12) {
2768 totalrank = 0;
2769 set_178(reg_178);
2770 FOR_POPULATED_RANKS_BACKWARDS {
2771 train_ram_at_178(info, channel, slot, rank,
2772 totalrank, reg_178, 0, niter,
2773 timings);
2774 totalrank++;
2775 }
2776 }
2777 }
2778
2779 set_178(reg178_center);
2780 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2781 u16 tm0;
2782
2783 tm0 =
2784 choose_training(info, channel, slot, rank, lane, timings,
2785 reg178_center);
2786 write_500(info, channel, tm0,
2787 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2788 write_500(info, channel,
2789 tm0 +
2790 info->training.
2791 lane_timings[1][channel][slot][rank][lane] -
2792 info->training.
2793 lane_timings[0][channel][slot][rank][lane],
2794 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
2795 }
2796
2797 totalrank = 0;
2798 FOR_POPULATED_RANKS_BACKWARDS {
2799 try_timing_offsets(info, channel, slot, rank, totalrank);
2800 totalrank++;
2801 }
Angel Ponsdea722b2021-03-26 14:11:12 +01002802 mchbar_write8(0x243, saved_243[0]);
2803 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002804 write_1d0(0, 0x142, 3, 1);
2805 info->training.reg178_center = reg178_center;
2806}
2807
2808static void ram_training(struct raminfo *info)
2809{
2810 u16 saved_fc4;
2811
Angel Ponsdea722b2021-03-26 14:11:12 +01002812 saved_fc4 = mchbar_read16(0xfc4);
2813 mchbar_write16(0xfc4, 0xffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002814
2815 if (info->revision >= 8)
2816 read_4090(info);
2817
2818 if (!try_cached_training(info))
2819 do_ram_training(info);
2820 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
2821 && info->clock_speed_index < 2)
2822 set_10b(info, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002823 mchbar_write16(0xfc4, saved_fc4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002824}
2825
Angel Pons7a87c922021-01-15 22:50:41 +01002826u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002827{
2828 int slot, rank, lane;
2829 u16 ret = 0;
2830
Angel Ponsdea722b2021-03-26 14:11:12 +01002831 if ((mchbar_read8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002832 return 384;
2833
2834 if (info->revision < 8)
2835 return 256;
2836
2837 for (slot = 0; slot < NUM_SLOTS; slot++)
2838 for (rank = 0; rank < NUM_RANKS; rank++)
2839 if (info->populated_ranks[channel][slot][rank])
2840 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002841 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002842 get_timing_register_addr
2843 (lane, 0, slot,
2844 rank), 9));
2845 return ret;
2846}
2847
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002848static void dmi_setup(void)
2849{
Angel Ponsdea722b2021-03-26 14:11:12 +01002850 gav(dmibar_read8(0x254));
2851 dmibar_write8(0x254, 1 << 0);
2852 dmibar_write16(0x1b8, 0x18f2);
2853 mchbar_clrsetbits16(0x48, ~0, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002854
Angel Ponsdea722b2021-03-26 14:11:12 +01002855 dmibar_setbits32(0xd68, 1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002856
2857 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
2858 DEFAULT_GPIOBASE | 0x38);
2859 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
2860}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002861
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002862void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002863{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002864 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02002865 u16 ggc;
2866 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002867
Angel Ponsdea722b2021-03-26 14:11:12 +01002868 x2ca8 = mchbar_read8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002869 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
2870 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Angel Ponsdea722b2021-03-26 14:11:12 +01002871 mchbar_write8(0x2ca8, 0);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02002872 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002873 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002874
2875 dmi_setup();
2876
Angel Ponsdea722b2021-03-26 14:11:12 +01002877 mchbar_write16(0x1170, 0xa880);
2878 mchbar_write8(0x11c1, 1 << 0);
2879 mchbar_write16(0x1170, 0xb880);
2880 mchbar_clrsetbits8(0x1210, ~0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002881
Angel Pons88dcb312021-04-26 17:10:28 +02002882 gfxsize = get_uint_option("gfx_uma_size", 0); /* 0 for 32MB */
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02002883
2884 ggc = 0xb00 | ((gfxsize + 5) << 4);
2885
Angel Pons16fe1e02020-07-22 16:12:33 +02002886 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002887
2888 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02002889 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002890
2891 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +01002892 mchbar_write8(0x2c30, 1 << 5);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002893 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Angel Ponsdea722b2021-03-26 14:11:12 +01002894 mchbar_setbits16(0x2c30, 1 << 9);
2895 mchbar_write16(0x2c32, 0x434);
2896 mchbar_clrsetbits32(0x2c44, ~0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02002897 pci_read_config8(GMA, MSAC); // = 0x2
2898 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01002899 RCBA8(0x2318);
2900 RCBA8(0x2318) = 0x47;
2901 RCBA8(0x2320);
2902 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002903 }
2904
Angel Ponsdea722b2021-03-26 14:11:12 +01002905 mchbar_clrsetbits32(0x30, ~0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002906
Angel Pons16fe1e02020-07-22 16:12:33 +02002907 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01002908 gav(RCBA32(0x3428));
2909 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002910}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002911
Angel Pons26681912021-01-15 21:36:28 +01002912static u8 get_bits_420(const u32 reg32)
2913{
2914 u8 val = 0;
2915 val |= (reg32 >> 4) & (1 << 0);
2916 val |= (reg32 >> 2) & (1 << 1);
2917 val |= (reg32 >> 0) & (1 << 2);
2918 return val;
2919}
2920
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002921void raminit(const int s3resume, const u8 *spd_addrmap)
2922{
Martin Roth468d02c2019-10-23 21:44:42 -06002923 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002924 struct raminfo info;
2925 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02002926 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002927
Angel Ponsdea722b2021-03-26 14:11:12 +01002928 x2ca8 = mchbar_read8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02002929
2930 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
2931
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002932 memset(&info, 0x5a, sizeof(info));
2933
2934 info.last_500_command[0] = 0;
2935 info.last_500_command[1] = 0;
2936
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002937 info.board_lane_delay[0] = 0x14;
2938 info.board_lane_delay[1] = 0x07;
2939 info.board_lane_delay[2] = 0x07;
2940 info.board_lane_delay[3] = 0x08;
2941 info.board_lane_delay[4] = 0x56;
2942 info.board_lane_delay[5] = 0x04;
2943 info.board_lane_delay[6] = 0x04;
2944 info.board_lane_delay[7] = 0x05;
2945 info.board_lane_delay[8] = 0x10;
2946
2947 info.training.reg_178 = 0;
2948 info.training.reg_10b = 0;
2949
Angel Ponsa3868292021-01-15 22:10:13 +01002950 /* Wait for some bit, maybe TXT clear. */
2951 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
2952 ;
2953
2954 /* Wait for ME to be ready */
Nico Huber56441322021-04-23 15:23:14 +00002955 intel_early_me_init();
2956 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002957
2958 /* before SPD */
2959 timestamp_add_now(101);
2960
Felix Held29a9c072018-07-29 01:34:45 +02002961 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002962 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
2963
2964 info.use_ecc = 1;
2965 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01002966 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002967 int v;
2968 int try;
2969 int addr;
2970 const u8 useful_addresses[] = {
2971 DEVICE_TYPE,
2972 MODULE_TYPE,
2973 DENSITY,
2974 RANKS_AND_DQ,
2975 MEMORY_BUS_WIDTH,
2976 TIMEBASE_DIVIDEND,
2977 TIMEBASE_DIVISOR,
2978 CYCLETIME,
2979 CAS_LATENCIES_LSB,
2980 CAS_LATENCIES_MSB,
2981 CAS_LATENCY_TIME,
2982 0x11, 0x12, 0x13, 0x14, 0x15,
2983 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
2984 0x1c, 0x1d,
2985 THERMAL_AND_REFRESH,
2986 0x20,
2987 REFERENCE_RAW_CARD_USED,
2988 RANK1_ADDRESS_MAPPING,
2989 0x75, 0x76, 0x77, 0x78,
2990 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
2991 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
2992 0x85, 0x86, 0x87, 0x88,
2993 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
2994 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
2995 0x95
2996 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01002997 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002998 continue;
2999 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003000 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003001 DEVICE_TYPE);
3002 if (v >= 0)
3003 break;
3004 }
3005 if (v < 0)
3006 continue;
3007 for (addr = 0;
3008 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003009 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003010 gav(info.
3011 spd[channel][0][useful_addresses
3012 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003013 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003014 useful_addresses
3015 [addr]));
3016 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3017 die("Only DDR3 is supported");
3018
3019 v = info.spd[channel][0][RANKS_AND_DQ];
3020 info.populated_ranks[channel][0][0] = 1;
3021 info.populated_ranks[channel][0][1] =
3022 ((v >> 3) & 7);
3023 if (((v >> 3) & 7) > 1)
3024 die("At most 2 ranks are supported");
3025 if ((v & 7) == 0 || (v & 7) > 2)
3026 die("Only x8 and x16 modules are supported");
3027 if ((info.
3028 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3029 && (info.
3030 spd[channel][slot][MODULE_TYPE] & 0xF)
3031 != 3)
3032 die("Registered memory is not supported");
3033 info.is_x16_module[channel][0] = (v & 7) - 1;
3034 info.density[channel][slot] =
3035 info.spd[channel][slot][DENSITY] & 0xF;
3036 if (!
3037 (info.
3038 spd[channel][slot][MEMORY_BUS_WIDTH] &
3039 0x18))
3040 info.use_ecc = 0;
3041 }
3042
3043 gav(0x55);
3044
3045 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3046 int v = 0;
3047 for (slot = 0; slot < NUM_SLOTS; slot++)
3048 for (rank = 0; rank < NUM_RANKS; rank++)
3049 v |= info.
3050 populated_ranks[channel][slot][rank]
3051 << (2 * slot + rank);
3052 info.populated_ranks_mask[channel] = v;
3053 }
3054
3055 gav(0x55);
3056
Angel Pons16fe1e02020-07-22 16:12:33 +02003057 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003058 }
3059
3060 /* after SPD */
3061 timestamp_add_now(102);
3062
Angel Ponsdea722b2021-03-26 14:11:12 +01003063 mchbar_clrbits8(0x2ca8, 1 << 1 | 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003064
3065 collect_system_info(&info);
3066 calculate_timings(&info);
3067
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003068 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003069 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003070 if (x2ca8 == 0 && (reg8 & 0x80)) {
3071 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3072 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3073 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3074 */
3075
3076 /* Clear bit7. */
3077
3078 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3079 (reg8 & ~(1 << 7)));
3080
3081 printk(BIOS_INFO,
3082 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003083 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003084 }
3085 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003086
3087 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003088 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3089 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003090
3091 compute_derived_timings(&info);
3092
Angel Pons56823f52021-01-16 11:27:33 +01003093 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003094
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003095 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003096
Angel Pons7a87c922021-01-15 22:50:41 +01003097 if (x2ca8 == 0)
3098 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003099
Angel Ponsdea722b2021-03-26 14:11:12 +01003100 mchbar_setbits32(0x2c80, 1 << 24);
3101 mchbar_write32(0x1804, mchbar_read32(0x1c04) & ~(1 << 27));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003102
Angel Ponsdea722b2021-03-26 14:11:12 +01003103 mchbar_read8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003104
3105 if (x2ca8 == 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003106 mchbar_clrbits8(0x2ca8, 3);
3107 mchbar_write8(0x2ca8, mchbar_read8(0x2ca8) + 4); // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003108 /* This issues a CPU reset without resetting the platform */
3109 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003110 /* Write back the S3 state to PM1_CNT to let the reset CPU
3111 know it also needs to take the s3 path. */
3112 if (s3resume)
3113 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3114 | (SLP_TYP_S3 << 10));
Angel Ponsdea722b2021-03-26 14:11:12 +01003115 mchbar_setbits32(0x1af0, 1 << 4);
Patrick Georgi546953c2014-11-29 10:38:17 +01003116 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003117 }
Angel Pons7a87c922021-01-15 22:50:41 +01003118
Angel Ponsdea722b2021-03-26 14:11:12 +01003119 mchbar_clrbits8(0x2ca8, 0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003120
Angel Ponsdea722b2021-03-26 14:11:12 +01003121 mchbar_clrbits32(0x2c80, 1 << 24);
Angel Ponsc627dc92020-09-22 17:06:44 +02003122
Angel Pons9addda32020-07-22 18:37:32 +02003123 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003124
3125 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003126 u8 x2c20 = (mchbar_read16(0x2c20) >> 8) & 3;
3127 u16 x2c10 = mchbar_read16(0x2c10);
3128 u16 value = mchbar_read16(0x2c00);
Angel Ponsc627dc92020-09-22 17:06:44 +02003129 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3130 value |= (1 << 7);
3131 else
3132 value &= ~(1 << 0);
3133
Angel Ponsdea722b2021-03-26 14:11:12 +01003134 mchbar_write16(0x2c00, value);
Angel Ponsc627dc92020-09-22 17:06:44 +02003135 }
3136
3137 udelay(1000); // !!!!
3138
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003139 write_1d0(0, 0x33d, 0, 0);
3140 write_500(&info, 0, 0, 0xb61, 0, 0);
3141 write_500(&info, 1, 0, 0xb61, 0, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01003142 mchbar_write32(0x1a30, 0);
3143 mchbar_write32(0x1a34, 0);
3144 mchbar_write16(0x614, 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3145 (info.populated_ranks[0][0][0] * 0xa0));
3146 mchbar_write16(0x616, 0x26a);
3147 mchbar_write32(0x134, 0x856000);
3148 mchbar_write32(0x160, 0x5ffffff);
3149 mchbar_clrsetbits32(0x114, ~0, 0xc2024440); // !!!!
3150 mchbar_clrsetbits32(0x118, ~0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003151 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003152 mchbar_write32(0x260 + (channel << 10), 0x30809ff |
3153 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003154 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003155 mchbar_write16(0x31c + (channel << 10), 0x101);
3156 mchbar_write16(0x360 + (channel << 10), 0x909);
3157 mchbar_write16(0x3a4 + (channel << 10), 0x101);
3158 mchbar_write16(0x3e8 + (channel << 10), 0x101);
3159 mchbar_write32(0x320 + (channel << 10), 0x29002900);
3160 mchbar_write32(0x324 + (channel << 10), 0);
3161 mchbar_write32(0x368 + (channel << 10), 0x32003200);
3162 mchbar_write16(0x352 + (channel << 10), 0x505);
3163 mchbar_write16(0x354 + (channel << 10), 0x3c3c);
3164 mchbar_write16(0x356 + (channel << 10), 0x1040);
3165 mchbar_write16(0x39a + (channel << 10), 0x73e4);
3166 mchbar_write16(0x3de + (channel << 10), 0x77ed);
3167 mchbar_write16(0x422 + (channel << 10), 0x1040);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003168 }
3169
3170 write_1d0(0x4, 0x151, 4, 1);
3171 write_1d0(0, 0x142, 3, 1);
3172 rdmsr(0x1ac); // !!!!
3173 write_500(&info, 1, 1, 0x6b3, 4, 1);
3174 write_500(&info, 1, 1, 0x6cf, 4, 1);
3175
Angel Pons244f4552021-01-15 20:41:36 +01003176 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003177
3178 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3179 populated_ranks[0]
3180 [0][0]) << 0),
3181 0x1d1, 3, 1);
3182 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003183 mchbar_write16(0x38e + (channel << 10), 0x5f5f);
3184 mchbar_write16(0x3d2 + (channel << 10), 0x5f5f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003185 }
3186
3187 set_334(0);
3188
3189 program_base_timings(&info);
3190
Angel Ponsdea722b2021-03-26 14:11:12 +01003191 mchbar_setbits8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003192
3193 write_1d0(0x2, 0x1d5, 2, 1);
3194 write_1d0(0x20, 0x166, 7, 1);
3195 write_1d0(0x0, 0xeb, 3, 1);
3196 write_1d0(0x0, 0xf3, 6, 1);
3197
Angel Pons3d357562021-01-16 14:46:45 +01003198 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3199 u8 a = 0;
3200 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3201 a = 3;
3202 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3203 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003204
Angel Pons3d357562021-01-16 14:46:45 +01003205 for (lane = 0; lane < 9; lane++) {
3206 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3207 rmw_500(&info, channel, addr, 6, 0xf, a);
3208 }
3209 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003210
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003211 if (s3resume) {
Elyes Haouas5e6b0f02022-09-13 09:55:49 +02003212 if (!info.cached_training) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003213 u32 reg32;
3214 printk(BIOS_ERR,
3215 "Couldn't find training data. Rebooting\n");
3216 reg32 = inl(DEFAULT_PMBASE + 0x04);
3217 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003218 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003219 }
3220 int tm;
3221 info.training = *info.cached_training;
3222 for (tm = 0; tm < 4; tm++)
3223 for (channel = 0; channel < NUM_CHANNELS; channel++)
3224 for (slot = 0; slot < NUM_SLOTS; slot++)
3225 for (rank = 0; rank < NUM_RANKS; rank++)
3226 for (lane = 0; lane < 9; lane++)
3227 write_500(&info,
3228 channel,
3229 info.training.
3230 lane_timings
3231 [tm][channel]
3232 [slot][rank]
3233 [lane],
3234 get_timing_register_addr
3235 (lane, tm,
3236 slot, rank),
3237 9, 0);
3238 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3239 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3240 }
3241
Angel Ponsdea722b2021-03-26 14:11:12 +01003242 mchbar_clrsetbits32(0x1f4, ~0, 1 << 17); // !!!!
3243 mchbar_write32(0x1f0, 0x1d000200);
3244 mchbar_setbits8(0x1f0, 1 << 0);
3245 while (mchbar_read8(0x1f0) & 1)
Angel Ponsc627dc92020-09-22 17:06:44 +02003246 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003247
3248 program_board_delay(&info);
3249
Angel Ponsdea722b2021-03-26 14:11:12 +01003250 mchbar_write8(0x5ff, 0);
3251 mchbar_write8(0x5ff, 1 << 7);
3252 mchbar_write8(0x5f4, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003253
Angel Ponsdea722b2021-03-26 14:11:12 +01003254 mchbar_clrbits32(0x130, 1 << 1); // | 2 when ?
3255 while (mchbar_read32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003256 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003257
3258 rmw_1d0(0x14b, 0x47, 0x30, 7);
3259 rmw_1d0(0xd6, 0x38, 7, 6);
3260 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003261
3262 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003263 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003264
Angel Ponsc627dc92020-09-22 17:06:44 +02003265 rmw_1d0(0x116, 0xe, 0, 4);
3266 rmw_1d0(0xae, 0x3e, 0, 6);
3267 rmw_1d0(0x300, 0x3e, 0, 6);
Angel Ponsdea722b2021-03-26 14:11:12 +01003268 mchbar_clrbits16(0x356, 1 << 15);
3269 mchbar_clrbits16(0x756, 1 << 15);
3270 mchbar_clrbits32(0x140, 7 << 24);
3271 mchbar_clrbits32(0x138, 7 << 24);
3272 mchbar_write32(0x130, 0x31111301);
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003273 /* Wait until REG130b0 is 1. */
Angel Ponsdea722b2021-03-26 14:11:12 +01003274 while (mchbar_read32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003275 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003276
Angel Pons26681912021-01-15 21:36:28 +01003277 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003278 {
Angel Pons26681912021-01-15 21:36:28 +01003279 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3280 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3281 value_a1 = val_xa1;
3282 rmw_1d0(0x320, 0x38, val_2f3, 6);
3283 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3284 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003285 }
3286
3287 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003288 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003289
Angel Pons244f4552021-01-15 20:41:36 +01003290 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003291 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003292 if ((mchbar_read32(0x144) & 0x1f) < 0x13)
Angel Pons26681912021-01-15 21:36:28 +01003293 value_a1 += 2;
3294 else
3295 value_a1 += 1;
3296
3297 if (value_a1 > 7)
3298 value_a1 = 7;
3299
3300 write_1d0(2, 0xae, 6, 1);
3301 write_1d0(2, 0x300, 6, 1);
3302 write_1d0(value_a1, 0x121, 3, 1);
3303 rmw_1d0(0xd6, 0x38, 4, 6);
3304 rmw_1d0(0x328, 0x38, 4, 6);
3305 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003306
3307 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003308 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003309
Angel Ponsdea722b2021-03-26 14:11:12 +01003310 mchbar_write32(0x130, 0x11111301 | info.populated_ranks[1][0][0] << 30 |
3311 info.populated_ranks[0][0][0] << 29);
3312 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003313 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003314
3315 {
Angel Pons26681912021-01-15 21:36:28 +01003316 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003317 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3318 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003319 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003320 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003321
3322 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003323 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003324
3325 set_334(1);
3326
Angel Ponsdea722b2021-03-26 14:11:12 +01003327 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003328
3329 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3330 write_500(&info, channel,
3331 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3332 1);
3333 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3334 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003335 mchbar_clrsetbits32(0x2d0, ~0xff0c01ff, 0x200000);
3336 mchbar_write16(0x6c0, 0x14a0);
3337 mchbar_clrsetbits32(0x6d0, ~0xff0000ff, 0x8000);
3338 mchbar_write16(0x232, 1 << 3);
Felix Held04be2dd2018-07-29 04:53:22 +02003339 /* 0x40004 or 0 depending on ? */
Angel Ponsdea722b2021-03-26 14:11:12 +01003340 mchbar_clrsetbits32(0x234, 0x40004, 0x40004);
3341 mchbar_clrsetbits32(0x34, 0x7, 5);
3342 mchbar_write32(0x128, 0x2150d05);
3343 mchbar_write8(0x12c, 0x1f);
3344 mchbar_write8(0x12d, 0x56);
3345 mchbar_write8(0x12e, 0x31);
3346 mchbar_write8(0x12f, 0);
3347 mchbar_write8(0x271, 1 << 1);
3348 mchbar_write8(0x671, 1 << 1);
3349 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003350 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003351 mchbar_write32(0x294 + (channel << 10),
3352 (info.populated_ranks_mask[channel] & 3) << 16);
3353 mchbar_clrsetbits32(0x134, ~0xfc01ffff, 0x10000);
3354 mchbar_clrsetbits32(0x134, ~0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003355 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003356 mchbar_clrsetbits32(0x260 + (channel << 10), 0xf << 20, 1 << 27 |
3357 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003358
3359 if (!s3resume)
3360 jedec_init(&info);
3361
3362 int totalrank = 0;
3363 for (channel = 0; channel < NUM_CHANNELS; channel++)
3364 for (slot = 0; slot < NUM_SLOTS; slot++)
3365 for (rank = 0; rank < NUM_RANKS; rank++)
3366 if (info.populated_ranks[channel][slot][rank]) {
3367 jedec_read(&info, channel, slot, rank,
3368 totalrank, 0xa, 0x400);
3369 totalrank++;
3370 }
3371
Angel Ponsdea722b2021-03-26 14:11:12 +01003372 mchbar_write8(0x12c, 0x9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003373
Angel Ponsdea722b2021-03-26 14:11:12 +01003374 mchbar_clrsetbits8(0x271, 0x3e, 0x0e);
3375 mchbar_clrsetbits8(0x671, 0x3e, 0x0e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003376
3377 if (!s3resume) {
3378 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003379 mchbar_write32(0x294 + (channel << 10),
3380 (info.populated_ranks_mask[channel] & 3) << 16);
3381 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003382 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003383 info.populated_ranks[channel][0][1] << 5);
3384 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003385 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003386 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003387
3388 {
3389 u8 a, b;
Angel Ponsdea722b2021-03-26 14:11:12 +01003390 a = mchbar_read8(0x243);
3391 b = mchbar_read8(0x643);
3392 mchbar_write8(0x243, a | 2);
3393 mchbar_write8(0x643, b | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003394 }
3395
3396 write_1d0(7, 0x19b, 3, 1);
3397 write_1d0(7, 0x1c0, 3, 1);
3398 write_1d0(4, 0x1c6, 4, 1);
3399 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003400 rmw_1d0(0x151, 0xf, 0x4, 4);
Angel Ponsdea722b2021-03-26 14:11:12 +01003401 mchbar_write32(0x584, 0xfffff);
3402 mchbar_write32(0x984, 0xfffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003403
3404 for (channel = 0; channel < NUM_CHANNELS; channel++)
3405 for (slot = 0; slot < NUM_SLOTS; slot++)
3406 for (rank = 0; rank < NUM_RANKS; rank++)
3407 if (info.
3408 populated_ranks[channel][slot]
3409 [rank])
3410 config_rank(&info, s3resume,
3411 channel, slot,
3412 rank);
3413
Angel Ponsdea722b2021-03-26 14:11:12 +01003414 mchbar_write8(0x243, 1);
3415 mchbar_write8(0x643, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416 }
3417
3418 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003419 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003420 write_26c(0, 0x820);
3421 write_26c(1, 0x820);
Angel Ponsdea722b2021-03-26 14:11:12 +01003422 mchbar_setbits32(0x130, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003423 /* end */
3424
3425 if (s3resume) {
3426 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003427 mchbar_write32(0x294 + (channel << 10),
3428 (info.populated_ranks_mask[channel] & 3) << 16);
3429 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003430 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003431 info.populated_ranks[channel][0][1] << 5);
3432 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003433 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003434 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 }
3436
Angel Ponsdea722b2021-03-26 14:11:12 +01003437 mchbar_clrbits32(0xfa4, 1 << 24 | 1 << 1);
3438 mchbar_write32(0xfb0, 0x2000e019);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003440 /* Before training. */
3441 timestamp_add_now(103);
3442
3443 if (!s3resume)
3444 ram_training(&info);
3445
3446 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003447 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448
3449 dump_timings(&info);
3450
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003451 program_modules_memory_map(&info, 0);
3452 program_total_memory_map(&info);
3453
3454 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Angel Ponsdea722b2021-03-26 14:11:12 +01003455 mchbar_write8(0x111, 0 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003456 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Angel Ponsdea722b2021-03-26 14:11:12 +01003457 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003458 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Angel Ponsdea722b2021-03-26 14:11:12 +01003459 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003460 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003461 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003462
Angel Ponsdea722b2021-03-26 14:11:12 +01003463 mchbar_clrbits32(0xfac, 1 << 31);
3464 mchbar_write32(0xfb4, 0x4800);
3465 mchbar_write32(0xfb8, (info.revision < 8) ? 0x20 : 0x0);
3466 mchbar_write32(0xe94, 0x7ffff);
3467 mchbar_write32(0xfc0, 0x80002040);
3468 mchbar_write32(0xfc4, 0x701246);
3469 mchbar_clrbits8(0xfc8, 0x70);
3470 mchbar_setbits32(0xe5c, 1 << 24);
3471 mchbar_clrsetbits32(0x1a70, 3 << 20, 2 << 20);
3472 mchbar_write32(0x50, 0x700b0);
3473 mchbar_write32(0x3c, 0x10);
3474 mchbar_clrsetbits8(0x1aa8, 0x3f, 0xa);
3475 mchbar_setbits8(0xff4, 1 << 1);
3476 mchbar_clrsetbits32(0xff8, 0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477
Angel Ponsdea722b2021-03-26 14:11:12 +01003478 mchbar_write32(0xd00, IOMMU_BASE2 | 1);
3479 mchbar_write32(0xd40, IOMMU_BASE1 | 1);
3480 mchbar_write32(0xdc0, IOMMU_BASE4 | 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003481
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003482 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3483 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3484 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003485
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003486 {
3487 u32 eax;
3488
3489 eax = info.fsb_frequency / 9;
Angel Ponsdea722b2021-03-26 14:11:12 +01003490 mchbar_clrsetbits32(0xfcc, 0x3ffff,
Felix Held04be2dd2018-07-29 04:53:22 +02003491 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003492 mchbar_write32(0x20, 0x33001);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493 }
3494
3495 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003496 mchbar_clrbits32(0x220 + (channel << 10), 0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003497 if (info.max_slots_used_in_channel == 1)
Angel Ponsdea722b2021-03-26 14:11:12 +01003498 mchbar_setbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003499 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003500 mchbar_clrbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003501
Angel Ponsdea722b2021-03-26 14:11:12 +01003502 mchbar_setbits8(0x241 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003503
Felix Held04be2dd2018-07-29 04:53:22 +02003504 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003505 || info.silicon_revision == 3))
Angel Ponsdea722b2021-03-26 14:11:12 +01003506 mchbar_setbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003507 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003508 mchbar_clrbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003509 }
3510
Angel Ponsdea722b2021-03-26 14:11:12 +01003511 mchbar_setbits32(0x115, 1 << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003512
3513 {
3514 u8 al;
3515 al = 0xd;
3516 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3517 al += 2;
3518 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Angel Ponsdea722b2021-03-26 14:11:12 +01003519 mchbar_write32(0x210, al << 16 | 0x20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003520 }
3521
3522 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003523 mchbar_write32(0x288 + (channel << 10), 0x70605040);
3524 mchbar_write32(0x28c + (channel << 10), 0xfffec080);
3525 mchbar_write32(0x290 + (channel << 10), 0x282091c |
3526 (info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003527 }
3528 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003529 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003530 reg1c = epbar_read32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003531 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003532 epbar_write32(EPVC1RCAP, reg1c); // OK
3533 mchbar_read8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003534 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Angel Ponsdea722b2021-03-26 14:11:12 +01003535 mchbar_setbits8(0x1210, 1 << 1);
3536 mchbar_write32(0x1200, 0x8800440);
3537 mchbar_write32(0x1204, 0x53ff0453);
3538 mchbar_write32(0x1208, 0x19002043);
3539 mchbar_write16(0x1214, 0x320);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003540
3541 if (info.revision == 0x10 || info.revision == 0x11) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003542 mchbar_write16(0x1214, 0x220);
3543 mchbar_setbits8(0x1210, 1 << 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003544 }
3545
Angel Ponsdea722b2021-03-26 14:11:12 +01003546 mchbar_setbits8(0x1214, 1 << 2);
3547 mchbar_write8(0x120c, 1);
3548 mchbar_write8(0x1218, 3);
3549 mchbar_write8(0x121a, 3);
3550 mchbar_write8(0x121c, 3);
3551 mchbar_write16(0xc14, 0);
3552 mchbar_write16(0xc20, 0);
3553 mchbar_write32(0x1c, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003554
3555 /* revision dependent here. */
3556
Angel Ponsdea722b2021-03-26 14:11:12 +01003557 mchbar_setbits16(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003558
3559 if (info.uma_enabled)
Angel Ponsdea722b2021-03-26 14:11:12 +01003560 mchbar_setbits32(0x11f4, 1 << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003561
Angel Ponsdea722b2021-03-26 14:11:12 +01003562 mchbar_setbits16(0x1230, 1 << 15);
3563 mchbar_setbits8(0x1214, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003564
3565 u8 bl, ebpb;
3566 u16 reg_1020;
3567
Angel Ponsdea722b2021-03-26 14:11:12 +01003568 reg_1020 = mchbar_read32(0x1020); // = 0x6c733c // OK
3569 mchbar_write8(0x1070, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003570
Angel Ponsdea722b2021-03-26 14:11:12 +01003571 mchbar_write32(0x1000, 0x100);
3572 mchbar_write8(0x1007, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003573
3574 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003575 mchbar_write16(0x1018, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003576 bl = reg_1020 >> 8;
3577 ebpb = reg_1020 & 0xff;
3578 } else {
3579 ebpb = 0;
3580 bl = 8;
3581 }
3582
3583 rdmsr(0x1a2);
3584
Angel Ponsdea722b2021-03-26 14:11:12 +01003585 mchbar_write32(0x1014, 0xffffffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003586
Angel Ponsdea722b2021-03-26 14:11:12 +01003587 mchbar_write32(0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * !!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003588
Angel Ponsdea722b2021-03-26 14:11:12 +01003589 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003590
Angel Ponsdea722b2021-03-26 14:11:12 +01003591 mchbar_clrsetbits8(0x123e, 0xf0, 0x60);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003592 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003593 mchbar_clrsetbits32(0x123c, 0xf << 20, 0x6 << 20);
3594 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 }
3596
Angel Pons34619172022-02-14 12:48:42 +01003597 const u64 heci_uma_addr =
3598 ((u64)
3599 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
3600 info.memory_reserved_for_heci_mb)) << 20;
3601
3602 setup_heci_uma(heci_uma_addr, info.memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003603
3604 if (info.uma_enabled) {
3605 u16 ax;
Angel Ponsdea722b2021-03-26 14:11:12 +01003606 mchbar_setbits32(0x11b0, 1 << 14);
3607 mchbar_setbits32(0x11b4, 1 << 14);
3608 mchbar_setbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609
Angel Ponsdea722b2021-03-26 14:11:12 +01003610 ax = mchbar_read16(0x1190) & 0xf00; // = 0x480a // OK
3611 mchbar_write16(0x1170, ax | (mchbar_read16(0x1170) & 0x107f) | 0x4080);
3612 mchbar_setbits16(0x1170, 1 << 12);
Felix Held04be2dd2018-07-29 04:53:22 +02003613
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003614 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003615
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616 u16 ecx;
Angel Ponsdea722b2021-03-26 14:11:12 +01003617 for (ecx = 0xffff; ecx && (mchbar_read16(0x1170) & (1 << 12)); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003618 ;
Angel Ponsdea722b2021-03-26 14:11:12 +01003619 mchbar_clrbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620 }
3621
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003622 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3623 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624 udelay(10000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003625 mchbar_write16(0x2ca8, 1 << 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627 udelay(1000);
3628 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003629 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3630
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631 if (!s3resume)
3632 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003633 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003634 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003635 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003636
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003637 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003638 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003639 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640}