blob: 945e139a7b955bf8405d34c495c25a2ac5562c7f [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++;
785 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
786 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
787 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
788 || (info->populated_ranks[1][0][0]
789 && info->populated_ranks[1][1][0]))
790 info->max_slots_used_in_channel = 2;
791 else
792 info->max_slots_used_in_channel = 1;
Angel Pons2ea8b942021-12-19 17:15:48 +0100793 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +0100794 mchbar_write32(0x244 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +0200795 ((info->revision < 8) ? 1 : 0x200) |
796 ((2 - info->max_slots_used_in_channel) << 17) |
797 (channel << 21) |
Angel Ponsdea722b2021-03-26 14:11:12 +0100798 (info->some_delay_1_cycle_floor << 18) | 0x9510);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100799 if (info->max_slots_used_in_channel == 1) {
800 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
801 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
802 } else {
803 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 */
804 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
805 || (count_ranks_in_channel(info, 1) ==
806 2)) ? 2 : 3;
807 }
808 for (channel = 0; channel < NUM_CHANNELS; channel++) {
809 int max_of_unk;
810 int min_of_unk_2;
811
812 int i, count;
813 int sum;
814
815 if (!info->populated_ranks_mask[channel])
816 continue;
817
818 max_of_unk = 0;
819 min_of_unk_2 = 32767;
820
821 sum = 0;
822 count = 0;
823 for (i = 0; i < 3; i++) {
824 int unk1;
825 if (info->revision < 8)
826 unk1 =
827 u8_FFFD1891[0][channel][info->
828 clock_speed_index]
829 [i];
830 else if (!
831 (info->revision >= 0x10
832 || info->revision_flag_1))
833 unk1 =
834 u8_FFFD1891[1][channel][info->
835 clock_speed_index]
836 [i];
837 else
838 unk1 = 0;
839 for (slot = 0; slot < NUM_SLOTS; slot++)
840 for (rank = 0; rank < NUM_RANKS; rank++) {
841 int a = 0;
842 int b = 0;
843
844 if (!info->
845 populated_ranks[channel][slot]
846 [rank])
847 continue;
848 if (extended_silicon_revision == 4
849 && (info->
850 populated_ranks_mask[channel] &
851 5) != 5) {
852 if ((info->
853 spd[channel][slot]
854 [REFERENCE_RAW_CARD_USED] &
855 0x1F) == 3) {
856 a = u16_ffd1178[0]
857 [info->
858 clock_speed_index];
859 b = u16_fe0eb8[0][info->
860 clock_speed_index];
861 } else
862 if ((info->
863 spd[channel][slot]
864 [REFERENCE_RAW_CARD_USED]
865 & 0x1F) == 5) {
866 a = u16_ffd1178[1]
867 [info->
868 clock_speed_index];
869 b = u16_fe0eb8[1][info->
870 clock_speed_index];
871 }
872 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100873 min_of_unk_2 = MIN(min_of_unk_2, a);
874 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100875 if (rank == 0) {
876 sum += a;
877 count++;
878 }
879 {
880 int t;
881 t = b +
882 u8_FFFD0EF8[channel]
883 [extended_silicon_revision]
884 [info->
885 mode4030[channel]][info->
886 clock_speed_index];
887 if (unk1 >= t)
888 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100889 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100890 unk1 - t);
891 }
892 }
893 {
894 int t =
895 u8_FFFD17E0[channel]
896 [extended_silicon_revision][info->
897 mode4030
898 [channel]]
899 [info->clock_speed_index] + min_of_unk_2;
900 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100901 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100902 }
903 }
904
Jacob Garber64fb4a32019-06-10 17:29:18 -0600905 if (count == 0)
906 die("No memory ranks found for channel %u\n", channel);
907
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100908 info->avg4044[channel] = sum / count;
909 info->max4048[channel] = max_of_unk;
910 }
911}
912
913static void jedec_read(struct raminfo *info,
914 int channel, int slot, int rank,
915 int total_rank, u8 addr3, unsigned int value)
916{
917 /* Handle mirrored mapping. */
918 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +0200919 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
920 ((addr3 >> 1) & 0x10);
Angel Ponsdea722b2021-03-26 14:11:12 +0100921
922 mchbar_clrsetbits8(0x271, 0x1f << 1, addr3);
923 mchbar_clrsetbits8(0x671, 0x1f << 1, addr3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100924
925 /* Handle mirrored mapping. */
926 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
927 value =
928 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
929 << 1);
930
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800931 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100932
Angel Ponsdea722b2021-03-26 14:11:12 +0100933 mchbar_clrsetbits8(0x271, 0x1f << 1, 1 << 1);
934 mchbar_clrsetbits8(0x671, 0x1f << 1, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100935
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800936 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100937}
938
939enum {
940 MR1_RZQ12 = 512,
941 MR1_RZQ2 = 64,
942 MR1_RZQ4 = 4,
943 MR1_ODS34OHM = 2
944};
945
946enum {
947 MR0_BT_INTERLEAVED = 8,
948 MR0_DLL_RESET_ON = 256
949};
950
951enum {
952 MR2_RTT_WR_DISABLED = 0,
953 MR2_RZQ2 = 1 << 10
954};
955
956static void jedec_init(struct raminfo *info)
957{
958 int write_recovery;
959 int channel, slot, rank;
960 int total_rank;
961 int dll_on;
962 int self_refresh_temperature;
963 int auto_self_refresh;
964
965 auto_self_refresh = 1;
966 self_refresh_temperature = 1;
967 if (info->board_lane_delay[3] <= 10) {
968 if (info->board_lane_delay[3] <= 8)
969 write_recovery = info->board_lane_delay[3] - 4;
970 else
971 write_recovery = 5;
972 } else {
973 write_recovery = 6;
974 }
975 FOR_POPULATED_RANKS {
976 auto_self_refresh &=
977 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
978 self_refresh_temperature &=
979 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
980 }
981 if (auto_self_refresh == 1)
982 self_refresh_temperature = 0;
983
984 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
985 || (info->populated_ranks[0][0][0]
986 && info->populated_ranks[0][1][0])
987 || (info->populated_ranks[1][0][0]
988 && info->populated_ranks[1][1][0]));
989
990 total_rank = 0;
991
992 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
993 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
994 int rzq_reg58e;
995
996 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
997 rzq_reg58e = 64;
998 rtt = MR1_RZQ2;
999 if (info->clock_speed_index != 0) {
1000 rzq_reg58e = 4;
1001 if (info->populated_ranks_mask[channel] == 3)
1002 rtt = MR1_RZQ4;
1003 }
1004 } else {
1005 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1006 rtt = MR1_RZQ12;
1007 rzq_reg58e = 64;
1008 rtt_wr = MR2_RZQ2;
1009 } else {
1010 rzq_reg58e = 4;
1011 rtt = MR1_RZQ4;
1012 }
1013 }
1014
Angel Ponsdea722b2021-03-26 14:11:12 +01001015 mchbar_write16(0x588 + (channel << 10), 0);
1016 mchbar_write16(0x58a + (channel << 10), 4);
1017 mchbar_write16(0x58c + (channel << 10), rtt | MR1_ODS34OHM);
1018 mchbar_write16(0x58e + (channel << 10), rzq_reg58e | 0x82);
1019 mchbar_write16(0x590 + (channel << 10), 0x1282);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001020
1021 for (slot = 0; slot < NUM_SLOTS; slot++)
1022 for (rank = 0; rank < NUM_RANKS; rank++)
1023 if (info->populated_ranks[channel][slot][rank]) {
1024 jedec_read(info, channel, slot, rank,
1025 total_rank, 0x28,
1026 rtt_wr | (info->
1027 clock_speed_index
1028 << 3)
1029 | (auto_self_refresh << 6) |
1030 (self_refresh_temperature <<
1031 7));
1032 jedec_read(info, channel, slot, rank,
1033 total_rank, 0x38, 0);
1034 jedec_read(info, channel, slot, rank,
1035 total_rank, 0x18,
1036 rtt | MR1_ODS34OHM);
1037 jedec_read(info, channel, slot, rank,
1038 total_rank, 6,
1039 (dll_on << 12) |
1040 (write_recovery << 9)
1041 | ((info->cas_latency - 4) <<
1042 4) | MR0_BT_INTERLEAVED |
1043 MR0_DLL_RESET_ON);
1044 total_rank++;
1045 }
1046 }
1047}
1048
1049static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1050{
Martin Roth468d02c2019-10-23 21:44:42 -06001051 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001052 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1053 unsigned int channel_0_non_interleaved;
1054
1055 FOR_ALL_RANKS {
1056 if (info->populated_ranks[channel][slot][rank]) {
1057 total_mb[channel] +=
1058 pre_jedec ? 256 : (256 << info->
1059 density[channel][slot] >> info->
1060 is_x16_module[channel][slot]);
Angel Ponsdea722b2021-03-26 14:11:12 +01001061 mchbar_write8(0x208 + rank + 2 * slot + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001062 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1063 (info->is_x16_module[channel][slot] |
1064 ((info->density[channel][slot] + 1) << 1))) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001065 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001066 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001067 mchbar_write16(0x200 + (channel << 10) + 4 * slot + 2 * rank,
1068 total_mb[channel] >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001069 }
1070
1071 info->total_memory_mb = total_mb[0] + total_mb[1];
1072
1073 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001074 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001075 info->non_interleaved_part_mb =
1076 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1077 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001078 mchbar_write32(0x100, channel_0_non_interleaved | info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001079 if (!pre_jedec)
Angel Ponsdea722b2021-03-26 14:11:12 +01001080 mchbar_write16(0x104, info->interleaved_part_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001081}
1082
1083static void program_board_delay(struct raminfo *info)
1084{
1085 int cas_latency_shift;
1086 int some_delay_ns;
1087 int some_delay_3_half_cycles;
1088
Martin Roth468d02c2019-10-23 21:44:42 -06001089 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001090 int high_multiplier;
1091 int lane_3_delay;
1092 int cas_latency_derived;
1093
1094 high_multiplier = 0;
1095 some_delay_ns = 200;
1096 some_delay_3_half_cycles = 4;
1097 cas_latency_shift = info->silicon_revision == 0
1098 || info->silicon_revision == 1 ? 1 : 0;
1099 if (info->revision < 8) {
1100 some_delay_ns = 600;
1101 cas_latency_shift = 0;
1102 }
1103 {
1104 int speed_bit;
1105 speed_bit =
1106 ((info->clock_speed_index > 1
1107 || (info->silicon_revision != 2
1108 && info->silicon_revision != 3))) ^ (info->revision >=
1109 0x10);
1110 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1111 3, 1);
1112 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1113 3, 1);
1114 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1115 && (info->silicon_revision == 2
1116 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001117 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001118 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001119 mchbar_write32(0x120, 1 << (info->max_slots_used_in_channel + 28) | 0x188e7f9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001120
Angel Ponsdea722b2021-03-26 14:11:12 +01001121 mchbar_write8(0x124, info->board_lane_delay[4] + (frequency_01(info) + 999) / 1000);
1122 mchbar_write16(0x125, 0x1360);
1123 mchbar_write8(0x127, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001124 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001125 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001126 high_multiplier = 1;
1127 some_delay_2_half_cycles = ps_to_halfcycles(info,
1128 ((3 *
1129 fsbcycle_ps(info))
1130 >> 1) +
1131 (halfcycle_ps(info)
1132 *
1133 reg178_min[info->
1134 clock_speed_index]
1135 >> 6)
1136 +
1137 4 *
1138 halfcycle_ps(info)
1139 + 2230);
1140 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001141 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001142 (frequency_11(info) * 2) * (28 -
1143 some_delay_2_half_cycles) /
1144 (frequency_11(info) * 2 -
1145 4 * (info->fsb_frequency))) >> 3, 7);
1146 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001147 if (mchbar_read8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001148 some_delay_3_half_cycles = 3;
1149 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001150 mchbar_setbits32(0x220 + (channel << 10), 0x18001117);
1151 mchbar_write32(0x224 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001152 (info->max_slots_used_in_channel - 1) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001153 (info->cas_latency - 5 - info->clock_speed_index)
1154 << 21 | (info->max_slots_used_in_channel +
1155 info->cas_latency - cas_latency_shift - 4) << 16 |
1156 (info->cas_latency - cas_latency_shift - 4) << 26 |
1157 (info->cas_latency - info->clock_speed_index +
Felix Held04be2dd2018-07-29 04:53:22 +02001158 info->max_slots_used_in_channel - 6) << 8);
Angel Ponsdea722b2021-03-26 14:11:12 +01001159 mchbar_write32(0x228 + (channel << 10), info->max_slots_used_in_channel);
1160 mchbar_write8(0x239 + (channel << 10), 32);
1161 mchbar_write32(0x248 + (channel << 10), high_multiplier << 24 |
1162 some_delay_3_half_cycles << 25 | 0x840000);
1163 mchbar_write32(0x278 + (channel << 10), 0xc362042);
1164 mchbar_write32(0x27c + (channel << 10), 0x8b000062);
1165 mchbar_write32(0x24c + (channel << 10),
1166 (!!info->clock_speed_index) << 17 |
1167 ((2 + info->clock_speed_index -
1168 (!!info->clock_speed_index))) << 12 | 0x10200);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001169
Angel Ponsdea722b2021-03-26 14:11:12 +01001170 mchbar_write8(0x267 + (channel << 10), 4);
1171 mchbar_write16(0x272 + (channel << 10), 0x155);
1172 mchbar_clrsetbits32(0x2bc + (channel << 10), 0xffffff, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001173
1174 write_500(info, channel,
1175 ((!info->populated_ranks[channel][1][1])
1176 | (!info->populated_ranks[channel][1][0] << 1)
1177 | (!info->populated_ranks[channel][0][1] << 2)
1178 | (!info->populated_ranks[channel][0][0] << 3)),
1179 0x4c9, 4, 1);
1180 }
1181
Angel Ponsdea722b2021-03-26 14:11:12 +01001182 mchbar_write8(0x2c4, (1 + (info->clock_speed_index != 0)) << 6 | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183 {
1184 u8 freq_divisor = 2;
1185 if (info->fsb_frequency == frequency_11(info))
1186 freq_divisor = 3;
1187 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1188 freq_divisor = 1;
1189 else
1190 freq_divisor = 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001191 mchbar_write32(0x2c0, freq_divisor << 11 | 0x6009c400);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001192 }
1193
1194 if (info->board_lane_delay[3] <= 10) {
1195 if (info->board_lane_delay[3] <= 8)
1196 lane_3_delay = info->board_lane_delay[3];
1197 else
1198 lane_3_delay = 10;
1199 } else {
1200 lane_3_delay = 12;
1201 }
1202 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1203 if (info->clock_speed_index > 1)
1204 cas_latency_derived++;
1205 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001206 mchbar_write32(0x240 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001207 ((info->clock_speed_index == 0) * 0x11000) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001208 0x1002100 | (2 + info->clock_speed_index) << 4 |
1209 (info->cas_latency - 3));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001210 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1211 0x609, 6, 1);
1212 write_500(info, channel,
1213 info->clock_speed_index + 2 * info->cas_latency - 7,
1214 0x601, 6, 1);
1215
Angel Ponsdea722b2021-03-26 14:11:12 +01001216 mchbar_write32(0x250 + (channel << 10),
1217 (lane_3_delay + info->clock_speed_index + 9) << 6 |
1218 info->board_lane_delay[7] << 2 |
1219 info->board_lane_delay[4] << 16 |
1220 info->board_lane_delay[1] << 25 |
1221 info->board_lane_delay[1] << 29 | 1);
1222 mchbar_write32(0x254 + (channel << 10),
1223 info->board_lane_delay[1] >> 3 |
1224 (info->board_lane_delay[8] + 4 * info->use_ecc) << 6 |
1225 0x80 | info->board_lane_delay[6] << 1 |
1226 info->board_lane_delay[2] << 28 |
1227 cas_latency_derived << 16 | 0x4700000);
1228 mchbar_write32(0x258 + (channel << 10),
1229 (info->board_lane_delay[5] + info->clock_speed_index + 9) << 12 |
1230 (info->clock_speed_index - info->cas_latency + 12) << 8 |
1231 info->board_lane_delay[2] << 17 |
1232 info->board_lane_delay[4] << 24 | 0x47);
1233 mchbar_write32(0x25c + (channel << 10),
1234 info->board_lane_delay[1] << 1 |
1235 info->board_lane_delay[0] << 8 | 0x1da50000);
1236 mchbar_write8(0x264 + (channel << 10), 0xff);
1237 mchbar_write8(0x5f8 + (channel << 10), cas_latency_shift << 3 | info->use_ecc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001238 }
1239
1240 program_modules_memory_map(info, 1);
1241
Angel Ponsdea722b2021-03-26 14:11:12 +01001242 mchbar_clrsetbits16(0x610, 0xfe3c,
1243 MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9 | 0x3c);
1244 mchbar_setbits16(0x612, 1 << 8);
1245 mchbar_setbits16(0x214, 0x3e00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001246 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001247 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001248 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001249 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001250 }
1251}
1252
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001253#define DEFAULT_PCI_MMIO_SIZE 2048
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001254
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001255static void program_total_memory_map(struct raminfo *info)
1256{
Angel Pons9333b742020-07-22 16:04:15 +02001257 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001259 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 unsigned int uma_base_igd;
1261 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001262 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001263 int memory_remap;
1264 unsigned int memory_map[8];
1265 int i;
1266 unsigned int current_limit;
1267 unsigned int tseg_base;
1268 int uma_size_igd = 0, uma_size_gtt = 0;
1269
1270 memset(memory_map, 0, sizeof(memory_map));
1271
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001273 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274 gav(t);
1275 const int uma_sizes_gtt[16] =
1276 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1277 /* Igd memory */
1278 const int uma_sizes_igd[16] = {
1279 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1280 256, 512
1281 };
1282
1283 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1284 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1285 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001286
Angel Ponse24f97c2021-04-02 22:42:53 +02001287 mmio_size = DEFAULT_PCI_MMIO_SIZE;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001288
Angel Pons9333b742020-07-22 16:04:15 +02001289 tom = info->total_memory_mb;
1290 if (tom == 4096)
1291 tom = 4032;
1292 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1293 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1294 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001295 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001296 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001298 remap_base = MAX(4096, touud);
1299 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001300 }
Angel Pons9333b742020-07-22 16:04:15 +02001301 if (touud > 4096)
1302 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001303 quickpath_reserved = 0;
1304
Angel Pons3ab19b32020-07-22 16:29:54 +02001305 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001306
Jacob Garber975a7e32019-06-10 16:32:47 -06001307 gav(t);
1308
1309 if (t & 0x800) {
1310 u32 shift = t >> 20;
1311 if (shift == 0)
1312 die("Quickpath value is 0\n");
1313 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001314 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001315
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001316 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001317 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001318
Angel Pons9333b742020-07-22 16:04:15 +02001319 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001320 uma_base_gtt = uma_base_igd - uma_size_gtt;
1321 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1322 if (!memory_remap)
1323 tseg_base -= quickpath_reserved;
1324 tseg_base = ALIGN_DOWN(tseg_base, 8);
1325
Angel Pons16fe1e02020-07-22 16:12:33 +02001326 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1327 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001328 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001329 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1330 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001331 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001332 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001333
1334 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001335 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1336 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001337 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001338 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339
1340 current_limit = 0;
1341 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1342 memory_map[1] = 4096;
1343 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001344 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001345 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001346 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1347 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001348 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001349 }
1350}
1351
1352static void collect_system_info(struct raminfo *info)
1353{
1354 u32 capid0[3];
1355 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001356 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001357
Angel Ponsb600d412021-01-16 16:33:48 +01001358 for (i = 0; i < 3; i++) {
1359 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1360 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1361 }
1362 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1363 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1364 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1365
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001366 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1367
1368 if ((capid0[1] >> 11) & 1)
1369 info->uma_enabled = 0;
1370 else
1371 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001372 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001373 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1374 info->silicon_revision = 0;
1375
1376 if (capid0[2] & 2) {
1377 info->silicon_revision = 0;
1378 info->max_supported_clock_speed_index = 2;
1379 for (channel = 0; channel < NUM_CHANNELS; channel++)
1380 if (info->populated_ranks[channel][0][0]
1381 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1382 3) {
1383 info->silicon_revision = 2;
1384 info->max_supported_clock_speed_index = 1;
1385 }
1386 } else {
1387 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1388 case 1:
1389 case 2:
1390 info->silicon_revision = 3;
1391 break;
1392 case 3:
1393 info->silicon_revision = 0;
1394 break;
1395 case 0:
1396 info->silicon_revision = 2;
1397 break;
1398 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001399 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001400 case 0x40:
1401 info->silicon_revision = 0;
1402 break;
1403 case 0x48:
1404 info->silicon_revision = 1;
1405 break;
1406 }
1407 }
1408}
1409
1410static void write_training_data(struct raminfo *info)
1411{
1412 int tm, channel, slot, rank, lane;
1413 if (info->revision < 8)
1414 return;
1415
1416 for (tm = 0; tm < 4; tm++)
1417 for (channel = 0; channel < NUM_CHANNELS; channel++)
1418 for (slot = 0; slot < NUM_SLOTS; slot++)
1419 for (rank = 0; rank < NUM_RANKS; rank++)
1420 for (lane = 0; lane < 9; lane++)
1421 write_500(info, channel,
1422 info->
1423 cached_training->
1424 lane_timings[tm]
1425 [channel][slot][rank]
1426 [lane],
1427 get_timing_register_addr
1428 (lane, tm, slot,
1429 rank), 9, 0);
1430 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1431 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1432}
1433
1434static void dump_timings(struct raminfo *info)
1435{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001437 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001439 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 slot, rank);
1441 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001442 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001444 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 read_500(info, channel,
1446 get_timing_register_addr
1447 (lane, i, slot, rank),
1448 9),
1449 info->training.
1450 lane_timings[i][channel][slot][rank]
1451 [lane]);
1452 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001453 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 }
1455 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001456 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001458 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460}
1461
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001462/* Read timings and other registers that need to be restored verbatim and
1463 put them to CBMEM.
1464 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465static void save_timings(struct raminfo *info)
1466{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001468 int channel, slot, rank, lane, i;
1469
1470 train = info->training;
1471 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1472 for (i = 0; i < 4; i++)
1473 train.lane_timings[i][channel][slot][rank][lane] =
1474 read_500(info, channel,
1475 get_timing_register_addr(lane, i, slot,
1476 rank), 9);
1477 train.reg_178 = read_1d0(0x178, 7);
1478 train.reg_10b = read_1d0(0x10b, 6);
1479
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001480 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1481 u32 reg32;
Angel Ponsdea722b2021-03-26 14:11:12 +01001482 reg32 = mchbar_read32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001483 train.reg274265[channel][0] = reg32 >> 16;
1484 train.reg274265[channel][1] = reg32 & 0xffff;
Angel Ponsdea722b2021-03-26 14:11:12 +01001485 train.reg274265[channel][2] = mchbar_read16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001486 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001487 train.reg2ca9_bit0 = mchbar_read8(0x2ca9) & 1;
1488 train.reg_6dc = mchbar_read32(0x6dc);
1489 train.reg_6e8 = mchbar_read32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001490
Arthur Heymansb3282092019-04-14 17:53:28 +02001491 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1492 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001493
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001495 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1496 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001497}
1498
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499static const struct ram_training *get_cached_training(void)
1500{
Shelley Chenad9cd682020-07-23 16:10:52 -07001501 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1502 MRC_CACHE_VERSION,
1503 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001504}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001505
Angel Pons4e722d02022-02-14 12:33:19 +01001506/* TODO: Remove */
1507#include "raminit_heci.c"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001508
1509static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1510{
1511 int ranks_in_channel;
1512 ranks_in_channel = info->populated_ranks[channel][0][0]
1513 + info->populated_ranks[channel][0][1]
1514 + info->populated_ranks[channel][1][0]
1515 + info->populated_ranks[channel][1][1];
1516
1517 /* empty channel */
1518 if (ranks_in_channel == 0)
1519 return 1;
1520
1521 if (ranks_in_channel != ranks)
1522 return 0;
1523 /* single slot */
1524 if (info->populated_ranks[channel][0][0] !=
1525 info->populated_ranks[channel][1][0])
1526 return 1;
1527 if (info->populated_ranks[channel][0][1] !=
1528 info->populated_ranks[channel][1][1])
1529 return 1;
1530 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1531 return 0;
1532 if (info->density[channel][0] != info->density[channel][1])
1533 return 0;
1534 return 1;
1535}
1536
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001537static void read_4090(struct raminfo *info)
1538{
1539 int i, channel, slot, rank, lane;
1540 for (i = 0; i < 2; i++)
1541 for (slot = 0; slot < NUM_SLOTS; slot++)
1542 for (rank = 0; rank < NUM_RANKS; rank++)
1543 for (lane = 0; lane < 9; lane++)
1544 info->training.
1545 lane_timings[0][i][slot][rank][lane]
1546 = 32;
1547
1548 for (i = 1; i < 4; i++)
1549 for (channel = 0; channel < NUM_CHANNELS; channel++)
1550 for (slot = 0; slot < NUM_SLOTS; slot++)
1551 for (rank = 0; rank < NUM_RANKS; rank++)
1552 for (lane = 0; lane < 9; lane++) {
1553 info->training.
1554 lane_timings[i][channel]
1555 [slot][rank][lane] =
1556 read_500(info, channel,
1557 get_timing_register_addr
1558 (lane, i, slot,
1559 rank), 9)
1560 + (i == 1) * 11; // !!!!
1561 }
1562
1563}
1564
1565static u32 get_etalon2(int flip, u32 addr)
1566{
1567 const u16 invmask[] = {
1568 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1569 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1570 };
1571 u32 ret;
1572 u32 comp4 = addr / 480;
1573 addr %= 480;
1574 u32 comp1 = addr & 0xf;
1575 u32 comp2 = (addr >> 4) & 1;
1576 u32 comp3 = addr >> 5;
1577
1578 if (comp4)
1579 ret = 0x1010101 << (comp4 - 1);
1580 else
1581 ret = 0;
1582 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1583 ret = ~ret;
1584
1585 return ret;
1586}
1587
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001588static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001589{
1590 msr_t msr = {.lo = 0, .hi = 0 };
1591
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001592 wrmsr(MTRR_PHYS_BASE(3), msr);
1593 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594}
1595
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001596static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597{
1598 msr_t msr;
1599 msr.lo = base | MTRR_TYPE_WRPROT;
1600 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001601 wrmsr(MTRR_PHYS_BASE(3), msr);
1602 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603 & 0xffffffff);
1604 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001605 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001606}
1607
1608static void flush_cache(u32 start, u32 size)
1609{
1610 u32 end;
1611 u32 addr;
1612
1613 end = start + (ALIGN_DOWN(size + 4096, 4096));
1614 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001615 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001616}
1617
1618static void clear_errors(void)
1619{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001620 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001621}
1622
1623static void write_testing(struct raminfo *info, int totalrank, int flip)
1624{
1625 int nwrites = 0;
1626 /* in 8-byte units. */
1627 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001628 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629
Patrick Rudolph819c2062019-11-29 19:27:37 +01001630 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001631 for (offset = 0; offset < 9 * 480; offset += 2) {
1632 write32(base + offset * 8, get_etalon2(flip, offset));
1633 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1634 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1635 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1636 nwrites += 4;
1637 if (nwrites >= 320) {
1638 clear_errors();
1639 nwrites = 0;
1640 }
1641 }
1642}
1643
1644static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1645{
1646 u8 failmask = 0;
1647 int i;
1648 int comp1, comp2, comp3;
1649 u32 failxor[2] = { 0, 0 };
1650
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001651 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001652
1653 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1654 for (comp1 = 0; comp1 < 4; comp1++)
1655 for (comp2 = 0; comp2 < 60; comp2++) {
1656 u32 re[4];
1657 u32 curroffset =
1658 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1659 read128((total_rank << 28) | (curroffset << 3),
1660 (u64 *) re);
1661 failxor[0] |=
1662 get_etalon2(flip, curroffset) ^ re[0];
1663 failxor[1] |=
1664 get_etalon2(flip, curroffset) ^ re[1];
1665 failxor[0] |=
1666 get_etalon2(flip, curroffset | 1) ^ re[2];
1667 failxor[1] |=
1668 get_etalon2(flip, curroffset | 1) ^ re[3];
1669 }
1670 for (i = 0; i < 8; i++)
1671 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1672 failmask |= 1 << i;
1673 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001674 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001675 flush_cache((total_rank << 28), 1728 * 5 * 4);
1676 return failmask;
1677}
1678
1679const u32 seed1[0x18] = {
1680 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1681 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1682 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1683 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1684 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1685 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1686};
1687
1688static u32 get_seed2(int a, int b)
1689{
1690 const u32 seed2[5] = {
1691 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1692 0x5b6db6db,
1693 };
1694 u32 r;
1695 r = seed2[(a + (a >= 10)) / 5];
1696 return b ? ~r : r;
1697}
1698
1699static int make_shift(int comp2, int comp5, int x)
1700{
1701 const u8 seed3[32] = {
1702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1703 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1704 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1705 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1706 };
1707
1708 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1709}
1710
1711static u32 get_etalon(int flip, u32 addr)
1712{
1713 u32 mask_byte = 0;
1714 int comp1 = (addr >> 1) & 1;
1715 int comp2 = (addr >> 3) & 0x1f;
1716 int comp3 = (addr >> 8) & 0xf;
1717 int comp4 = (addr >> 12) & 0xf;
1718 int comp5 = (addr >> 16) & 0x1f;
1719 u32 mask_bit = ~(0x10001 << comp3);
1720 u32 part1;
1721 u32 part2;
1722 int byte;
1723
1724 part2 =
1725 ((seed1[comp5] >>
1726 make_shift(comp2, comp5,
1727 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1728 part1 =
1729 ((seed1[comp5] >>
1730 make_shift(comp2, comp5,
1731 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1732
1733 for (byte = 0; byte < 4; byte++)
1734 if ((get_seed2(comp5, comp4) >>
1735 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1736 mask_byte |= 0xff << (8 * byte);
1737
1738 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1739 (comp3 + 16));
1740}
1741
1742static void
1743write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1744 char flip)
1745{
1746 int i;
1747 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001748 write32p((totalrank << 28) | (region << 25) | (block << 16) |
1749 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750}
1751
1752static u8
1753check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1754 char flip)
1755{
1756 u8 failmask = 0;
1757 u32 failxor[2];
1758 int i;
1759 int comp1, comp2, comp3;
1760
1761 failxor[0] = 0;
1762 failxor[1] = 0;
1763
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001764 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001765 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
1766 for (comp1 = 0; comp1 < 16; comp1++)
1767 for (comp2 = 0; comp2 < 64; comp2++) {
1768 u32 addr =
1769 (totalrank << 28) | (region << 25) | (block
1770 << 16)
1771 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
1772 2);
1773 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001774 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001775 }
1776 for (i = 0; i < 8; i++)
1777 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1778 failmask |= 1 << i;
1779 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001780 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001781 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
1782 return failmask;
1783}
1784
1785static int check_bounded(unsigned short *vals, u16 bound)
1786{
1787 int i;
1788
1789 for (i = 0; i < 8; i++)
1790 if (vals[i] < bound)
1791 return 0;
1792 return 1;
1793}
1794
1795enum state {
1796 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
1797};
1798
1799static int validate_state(enum state *in)
1800{
1801 int i;
1802 for (i = 0; i < 8; i++)
1803 if (in[i] != COMPLETE)
1804 return 0;
1805 return 1;
1806}
1807
1808static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001809do_fsm(enum state *state, u16 *counter,
1810 u8 fail_mask, int margin, int uplimit,
1811 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001812{
1813 int lane;
1814
1815 for (lane = 0; lane < 8; lane++) {
1816 int is_fail = (fail_mask >> lane) & 1;
1817 switch (state[lane]) {
1818 case BEFORE_USABLE:
1819 if (!is_fail) {
1820 counter[lane] = 1;
1821 state[lane] = AT_USABLE;
1822 break;
1823 }
1824 counter[lane] = 0;
1825 state[lane] = BEFORE_USABLE;
1826 break;
1827 case AT_USABLE:
1828 if (!is_fail) {
1829 ++counter[lane];
1830 if (counter[lane] >= margin) {
1831 state[lane] = AT_MARGIN;
1832 res_low[lane] = val - margin + 1;
1833 break;
1834 }
1835 state[lane] = 1;
1836 break;
1837 }
1838 counter[lane] = 0;
1839 state[lane] = BEFORE_USABLE;
1840 break;
1841 case AT_MARGIN:
1842 if (is_fail) {
1843 state[lane] = COMPLETE;
1844 res_high[lane] = val - 1;
1845 } else {
1846 counter[lane]++;
1847 state[lane] = AT_MARGIN;
1848 if (val == uplimit) {
1849 state[lane] = COMPLETE;
1850 res_high[lane] = uplimit;
1851 }
1852 }
1853 break;
1854 case COMPLETE:
1855 break;
1856 }
1857 }
1858}
1859
1860static void
1861train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
1862 u8 total_rank, u8 reg_178, int first_run, int niter,
1863 timing_bounds_t * timings)
1864{
1865 int lane;
1866 enum state state[8];
1867 u16 count[8];
1868 u8 lower_usable[8];
1869 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02001870 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02001872 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001873
Elyes HAOUAS019a2532019-05-25 11:13:43 +02001874 for (i = 0; i < 8; i++)
1875 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001876
1877 if (!first_run) {
1878 int is_all_ok = 1;
1879 for (lane = 0; lane < 8; lane++)
1880 if (timings[reg_178][channel][slot][rank][lane].
1881 smallest ==
1882 timings[reg_178][channel][slot][rank][lane].
1883 largest) {
1884 timings[reg_178][channel][slot][rank][lane].
1885 smallest = 0;
1886 timings[reg_178][channel][slot][rank][lane].
1887 largest = 0;
1888 is_all_ok = 0;
1889 }
1890 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001891 for (i = 0; i < 8; i++)
1892 state[i] = COMPLETE;
1893 }
1894 }
1895
1896 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
1897 u8 failmask = 0;
1898 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
1899 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
1900 failmask = check_testing(info, total_rank, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01001901 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001902 do_fsm(state, count, failmask, 5, 47, lower_usable,
1903 upper_usable, reg1b3);
1904 }
1905
1906 if (reg1b3) {
1907 write_1d0(0, 0x1b3, 6, 1);
1908 write_1d0(0, 0x1a3, 6, 1);
1909 for (lane = 0; lane < 8; lane++) {
1910 if (state[lane] == COMPLETE) {
1911 timings[reg_178][channel][slot][rank][lane].
1912 smallest =
1913 lower_usable[lane] +
1914 (info->training.
1915 lane_timings[0][channel][slot][rank][lane]
1916 & 0x3F) - 32;
1917 timings[reg_178][channel][slot][rank][lane].
1918 largest =
1919 upper_usable[lane] +
1920 (info->training.
1921 lane_timings[0][channel][slot][rank][lane]
1922 & 0x3F) - 32;
1923 }
1924 }
1925 }
1926
1927 if (!first_run) {
1928 for (lane = 0; lane < 8; lane++)
1929 if (state[lane] == COMPLETE) {
1930 write_500(info, channel,
1931 timings[reg_178][channel][slot][rank]
1932 [lane].smallest,
1933 get_timing_register_addr(lane, 0,
1934 slot, rank),
1935 9, 1);
1936 write_500(info, channel,
1937 timings[reg_178][channel][slot][rank]
1938 [lane].smallest +
1939 info->training.
1940 lane_timings[1][channel][slot][rank]
1941 [lane]
1942 -
1943 info->training.
1944 lane_timings[0][channel][slot][rank]
1945 [lane], get_timing_register_addr(lane,
1946 1,
1947 slot,
1948 rank),
1949 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02001950 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001951 } else
Felix Held04be2dd2018-07-29 04:53:22 +02001952 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001953
1954 do {
1955 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001956 for (i = 0; i < niter; i++) {
1957 if (failmask == 0xFF)
1958 break;
1959 failmask |=
1960 check_testing_type2(info, total_rank, 2, i,
1961 0);
1962 failmask |=
1963 check_testing_type2(info, total_rank, 3, i,
1964 1);
1965 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001966 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02001968 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969 if ((1 << lane) & failmask) {
1970 if (timings[reg_178][channel]
1971 [slot][rank][lane].
1972 largest <=
1973 timings[reg_178][channel]
1974 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02001975 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001976 [lane] = -1;
1977 else {
Felix Held04be2dd2018-07-29 04:53:22 +02001978 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001979 [lane] = 0;
1980 timings[reg_178]
1981 [channel][slot]
1982 [rank][lane].
1983 smallest++;
1984 write_500(info, channel,
1985 timings
1986 [reg_178]
1987 [channel]
1988 [slot][rank]
1989 [lane].
1990 smallest,
1991 get_timing_register_addr
1992 (lane, 0,
1993 slot, rank),
1994 9, 1);
1995 write_500(info, channel,
1996 timings
1997 [reg_178]
1998 [channel]
1999 [slot][rank]
2000 [lane].
2001 smallest +
2002 info->
2003 training.
2004 lane_timings
2005 [1][channel]
2006 [slot][rank]
2007 [lane]
2008 -
2009 info->
2010 training.
2011 lane_timings
2012 [0][channel]
2013 [slot][rank]
2014 [lane],
2015 get_timing_register_addr
2016 (lane, 1,
2017 slot, rank),
2018 9, 1);
2019 }
2020 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002021 num_successfully_checked[lane]
2022 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002023 }
2024 }
Felix Held04be2dd2018-07-29 04:53:22 +02002025 while (!check_bounded(num_successfully_checked, 2))
2026 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002027
2028 for (lane = 0; lane < 8; lane++)
2029 if (state[lane] == COMPLETE) {
2030 write_500(info, channel,
2031 timings[reg_178][channel][slot][rank]
2032 [lane].largest,
2033 get_timing_register_addr(lane, 0,
2034 slot, rank),
2035 9, 1);
2036 write_500(info, channel,
2037 timings[reg_178][channel][slot][rank]
2038 [lane].largest +
2039 info->training.
2040 lane_timings[1][channel][slot][rank]
2041 [lane]
2042 -
2043 info->training.
2044 lane_timings[0][channel][slot][rank]
2045 [lane], get_timing_register_addr(lane,
2046 1,
2047 slot,
2048 rank),
2049 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002050 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002051 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002052 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002053
2054 do {
2055 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002056 for (i = 0; i < niter; i++) {
2057 if (failmask == 0xFF)
2058 break;
2059 failmask |=
2060 check_testing_type2(info, total_rank, 2, i,
2061 0);
2062 failmask |=
2063 check_testing_type2(info, total_rank, 3, i,
2064 1);
2065 }
2066
Angel Ponsdea722b2021-03-26 14:11:12 +01002067 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002068 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002069 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002070 if ((1 << lane) & failmask) {
2071 if (timings[reg_178][channel]
2072 [slot][rank][lane].
2073 largest <=
2074 timings[reg_178][channel]
2075 [slot][rank][lane].
2076 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002077 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002078 [lane] = -1;
2079 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002080 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002081 [lane] = 0;
2082 timings[reg_178]
2083 [channel][slot]
2084 [rank][lane].
2085 largest--;
2086 write_500(info, channel,
2087 timings
2088 [reg_178]
2089 [channel]
2090 [slot][rank]
2091 [lane].
2092 largest,
2093 get_timing_register_addr
2094 (lane, 0,
2095 slot, rank),
2096 9, 1);
2097 write_500(info, channel,
2098 timings
2099 [reg_178]
2100 [channel]
2101 [slot][rank]
2102 [lane].
2103 largest +
2104 info->
2105 training.
2106 lane_timings
2107 [1][channel]
2108 [slot][rank]
2109 [lane]
2110 -
2111 info->
2112 training.
2113 lane_timings
2114 [0][channel]
2115 [slot][rank]
2116 [lane],
2117 get_timing_register_addr
2118 (lane, 1,
2119 slot, rank),
2120 9, 1);
2121 }
2122 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002123 num_successfully_checked[lane]
2124 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002125 }
2126 }
2127 }
Felix Held04be2dd2018-07-29 04:53:22 +02002128 while (!check_bounded(num_successfully_checked, 3))
2129 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002130
2131 for (lane = 0; lane < 8; lane++) {
2132 write_500(info, channel,
2133 info->training.
2134 lane_timings[0][channel][slot][rank][lane],
2135 get_timing_register_addr(lane, 0, slot, rank),
2136 9, 1);
2137 write_500(info, channel,
2138 info->training.
2139 lane_timings[1][channel][slot][rank][lane],
2140 get_timing_register_addr(lane, 1, slot, rank),
2141 9, 1);
2142 if (timings[reg_178][channel][slot][rank][lane].
2143 largest <=
2144 timings[reg_178][channel][slot][rank][lane].
2145 smallest) {
2146 timings[reg_178][channel][slot][rank][lane].
2147 largest = 0;
2148 timings[reg_178][channel][slot][rank][lane].
2149 smallest = 0;
2150 }
2151 }
2152 }
2153}
2154
2155static void set_10b(struct raminfo *info, u8 val)
2156{
2157 int channel;
2158 int slot, rank;
2159 int lane;
2160
2161 if (read_1d0(0x10b, 6) == val)
2162 return;
2163
2164 write_1d0(val, 0x10b, 6, 1);
2165
2166 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2167 u16 reg_500;
2168 reg_500 = read_500(info, channel,
2169 get_timing_register_addr(lane, 0, slot,
2170 rank), 9);
2171 if (val == 1) {
2172 if (lut16[info->clock_speed_index] <= reg_500)
2173 reg_500 -= lut16[info->clock_speed_index];
2174 else
2175 reg_500 = 0;
2176 } else {
2177 reg_500 += lut16[info->clock_speed_index];
2178 }
2179 write_500(info, channel, reg_500,
2180 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2181 }
2182}
2183
2184static void set_ecc(int onoff)
2185{
2186 int channel;
2187 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2188 u8 t;
Angel Ponsdea722b2021-03-26 14:11:12 +01002189 t = mchbar_read8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002190 if (onoff)
2191 t |= 1;
2192 else
2193 t &= ~1;
Angel Ponsdea722b2021-03-26 14:11:12 +01002194 mchbar_write8((channel << 10) + 0x5f8, t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002195 }
2196}
2197
2198static void set_178(u8 val)
2199{
2200 if (val >= 31)
2201 val = val - 31;
2202 else
2203 val = 63 - val;
2204
2205 write_1d0(2 * val, 0x178, 7, 1);
2206}
2207
2208static void
2209write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2210 int type)
2211{
2212 int lane;
2213
2214 for (lane = 0; lane < 8; lane++)
2215 write_500(info, channel,
2216 info->training.
2217 lane_timings[type][channel][slot][rank][lane],
2218 get_timing_register_addr(lane, type, slot, rank), 9,
2219 0);
2220}
2221
2222static void
2223try_timing_offsets(struct raminfo *info, int channel,
2224 int slot, int rank, int totalrank)
2225{
2226 u16 count[8];
2227 enum state state[8];
2228 u8 lower_usable[8], upper_usable[8];
2229 int lane;
2230 int i;
2231 int flip = 1;
2232 int timing_offset;
2233
2234 for (i = 0; i < 8; i++)
2235 state[i] = BEFORE_USABLE;
2236
2237 memset(count, 0, sizeof(count));
2238
2239 for (lane = 0; lane < 8; lane++)
2240 write_500(info, channel,
2241 info->training.
2242 lane_timings[2][channel][slot][rank][lane] + 32,
2243 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2244
2245 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2246 timing_offset++) {
2247 u8 failmask;
2248 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2249 failmask = 0;
2250 for (i = 0; i < 2 && failmask != 0xff; i++) {
2251 flip = !flip;
2252 write_testing(info, totalrank, flip);
2253 failmask |= check_testing(info, totalrank, flip);
2254 }
2255 do_fsm(state, count, failmask, 10, 63, lower_usable,
2256 upper_usable, timing_offset);
2257 }
2258 write_1d0(0, 0x1bb, 6, 1);
2259 dump_timings(info);
2260 if (!validate_state(state))
2261 die("Couldn't discover DRAM timings (1)\n");
2262
2263 for (lane = 0; lane < 8; lane++) {
2264 u8 bias = 0;
2265
2266 if (info->silicon_revision) {
2267 int usable_length;
2268
2269 usable_length = upper_usable[lane] - lower_usable[lane];
2270 if (usable_length >= 20) {
2271 bias = usable_length / 2 - 10;
2272 if (bias >= 2)
2273 bias = 2;
2274 }
2275 }
2276 write_500(info, channel,
2277 info->training.
2278 lane_timings[2][channel][slot][rank][lane] +
2279 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2280 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2281 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2282 info->training.lane_timings[2][channel][slot][rank][lane] +
2283 lower_usable[lane];
2284 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2285 info->training.lane_timings[2][channel][slot][rank][lane] +
2286 upper_usable[lane];
2287 info->training.timing2_offset[channel][slot][rank][lane] =
2288 info->training.lane_timings[2][channel][slot][rank][lane];
2289 }
2290}
2291
2292static u8
2293choose_training(struct raminfo *info, int channel, int slot, int rank,
2294 int lane, timing_bounds_t * timings, u8 center_178)
2295{
2296 u16 central_weight;
2297 u16 side_weight;
2298 unsigned int sum = 0, count = 0;
2299 u8 span;
2300 u8 lower_margin, upper_margin;
2301 u8 reg_178;
2302 u8 result;
2303
2304 span = 12;
2305 central_weight = 20;
2306 side_weight = 20;
2307 if (info->silicon_revision == 1 && channel == 1) {
2308 central_weight = 5;
2309 side_weight = 20;
2310 if ((info->
2311 populated_ranks_mask[1] ^ (info->
2312 populated_ranks_mask[1] >> 2)) &
2313 1)
2314 span = 18;
2315 }
2316 if ((info->populated_ranks_mask[0] & 5) == 5) {
2317 central_weight = 20;
2318 side_weight = 20;
2319 }
2320 if (info->clock_speed_index >= 2
2321 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2322 if (info->silicon_revision == 1) {
2323 switch (channel) {
2324 case 0:
2325 if (lane == 1) {
2326 central_weight = 10;
2327 side_weight = 20;
2328 }
2329 break;
2330 case 1:
2331 if (lane == 6) {
2332 side_weight = 5;
2333 central_weight = 20;
2334 }
2335 break;
2336 }
2337 }
2338 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2339 side_weight = 5;
2340 central_weight = 20;
2341 }
2342 }
2343 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2344 reg_178 += span) {
2345 u8 smallest;
2346 u8 largest;
2347 largest = timings[reg_178][channel][slot][rank][lane].largest;
2348 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2349 if (largest - smallest + 1 >= 5) {
2350 unsigned int weight;
2351 if (reg_178 == center_178)
2352 weight = central_weight;
2353 else
2354 weight = side_weight;
2355 sum += weight * (largest + smallest);
2356 count += weight;
2357 }
2358 }
2359 dump_timings(info);
2360 if (count == 0)
2361 die("Couldn't discover DRAM timings (2)\n");
2362 result = sum / (2 * count);
2363 lower_margin =
2364 result - timings[center_178][channel][slot][rank][lane].smallest;
2365 upper_margin =
2366 timings[center_178][channel][slot][rank][lane].largest - result;
2367 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002368 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002369 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002370 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002371 return result;
2372}
2373
2374#define STANDARD_MIN_MARGIN 5
2375
2376static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2377{
2378 u16 margin[64];
2379 int lane, rank, slot, channel;
2380 u8 reg178;
2381 int count = 0, sum = 0;
2382
2383 for (reg178 = reg178_min[info->clock_speed_index];
2384 reg178 < reg178_max[info->clock_speed_index];
2385 reg178 += reg178_step[info->clock_speed_index]) {
2386 margin[reg178] = -1;
2387 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2388 int curmargin =
2389 timings[reg178][channel][slot][rank][lane].largest -
2390 timings[reg178][channel][slot][rank][lane].
2391 smallest + 1;
2392 if (curmargin < margin[reg178])
2393 margin[reg178] = curmargin;
2394 }
2395 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2396 u16 weight;
2397 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2398 sum += weight * reg178;
2399 count += weight;
2400 }
2401 }
2402 dump_timings(info);
2403 if (count == 0)
2404 die("Couldn't discover DRAM timings (3)\n");
2405
2406 u8 threshold;
2407
2408 for (threshold = 30; threshold >= 5; threshold--) {
2409 int usable_length = 0;
2410 int smallest_fount = 0;
2411 for (reg178 = reg178_min[info->clock_speed_index];
2412 reg178 < reg178_max[info->clock_speed_index];
2413 reg178 += reg178_step[info->clock_speed_index])
2414 if (margin[reg178] >= threshold) {
2415 usable_length +=
2416 reg178_step[info->clock_speed_index];
2417 info->training.reg178_largest =
2418 reg178 -
2419 2 * reg178_step[info->clock_speed_index];
2420
2421 if (!smallest_fount) {
2422 smallest_fount = 1;
2423 info->training.reg178_smallest =
2424 reg178 +
2425 reg178_step[info->
2426 clock_speed_index];
2427 }
2428 }
2429 if (usable_length >= 0x21)
2430 break;
2431 }
2432
2433 return sum / count;
2434}
2435
2436static int check_cached_sanity(struct raminfo *info)
2437{
2438 int lane;
2439 int slot, rank;
2440 int channel;
2441
2442 if (!info->cached_training)
2443 return 0;
2444
2445 for (channel = 0; channel < NUM_CHANNELS; channel++)
2446 for (slot = 0; slot < NUM_SLOTS; slot++)
2447 for (rank = 0; rank < NUM_RANKS; rank++)
2448 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2449 u16 cached_value, estimation_value;
2450 cached_value =
2451 info->cached_training->
2452 lane_timings[1][channel][slot][rank]
2453 [lane];
2454 if (cached_value >= 0x18
2455 && cached_value <= 0x1E7) {
2456 estimation_value =
2457 info->training.
2458 lane_timings[1][channel]
2459 [slot][rank][lane];
2460 if (estimation_value <
2461 cached_value - 24)
2462 return 0;
2463 if (estimation_value >
2464 cached_value + 24)
2465 return 0;
2466 }
2467 }
2468 return 1;
2469}
2470
2471static int try_cached_training(struct raminfo *info)
2472{
2473 u8 saved_243[2];
2474 u8 tm;
2475
2476 int channel, slot, rank, lane;
2477 int flip = 1;
2478 int i, j;
2479
2480 if (!check_cached_sanity(info))
2481 return 0;
2482
2483 info->training.reg178_center = info->cached_training->reg178_center;
2484 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2485 info->training.reg178_largest = info->cached_training->reg178_largest;
2486 memcpy(&info->training.timing_bounds,
2487 &info->cached_training->timing_bounds,
2488 sizeof(info->training.timing_bounds));
2489 memcpy(&info->training.timing_offset,
2490 &info->cached_training->timing_offset,
2491 sizeof(info->training.timing_offset));
2492
2493 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002494 saved_243[0] = mchbar_read8(0x243);
2495 saved_243[1] = mchbar_read8(0x643);
2496 mchbar_write8(0x243, saved_243[0] | 2);
2497 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002498 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002499 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002500 if (read_1d0(0x10b, 6) & 1)
2501 set_10b(info, 0);
2502 for (tm = 0; tm < 2; tm++) {
2503 int totalrank;
2504
2505 set_178(tm ? info->cached_training->reg178_largest : info->
2506 cached_training->reg178_smallest);
2507
2508 totalrank = 0;
2509 /* Check timing ranges. With i == 0 we check smallest one and with
2510 i == 1 the largest bound. With j == 0 we check that on the bound
2511 it still works whereas with j == 1 we check that just outside of
2512 bound we fail.
2513 */
2514 FOR_POPULATED_RANKS_BACKWARDS {
2515 for (i = 0; i < 2; i++) {
2516 for (lane = 0; lane < 8; lane++) {
2517 write_500(info, channel,
2518 info->cached_training->
2519 timing2_bounds[channel][slot]
2520 [rank][lane][i],
2521 get_timing_register_addr(lane,
2522 3,
2523 slot,
2524 rank),
2525 9, 1);
2526
2527 if (!i)
2528 write_500(info, channel,
2529 info->
2530 cached_training->
2531 timing2_offset
2532 [channel][slot][rank]
2533 [lane],
2534 get_timing_register_addr
2535 (lane, 2, slot, rank),
2536 9, 1);
2537 write_500(info, channel,
2538 i ? info->cached_training->
2539 timing_bounds[tm][channel]
2540 [slot][rank][lane].
2541 largest : info->
2542 cached_training->
2543 timing_bounds[tm][channel]
2544 [slot][rank][lane].smallest,
2545 get_timing_register_addr(lane,
2546 0,
2547 slot,
2548 rank),
2549 9, 1);
2550 write_500(info, channel,
2551 info->cached_training->
2552 timing_offset[channel][slot]
2553 [rank][lane] +
2554 (i ? info->cached_training->
2555 timing_bounds[tm][channel]
2556 [slot][rank][lane].
2557 largest : info->
2558 cached_training->
2559 timing_bounds[tm][channel]
2560 [slot][rank][lane].
2561 smallest) - 64,
2562 get_timing_register_addr(lane,
2563 1,
2564 slot,
2565 rank),
2566 9, 1);
2567 }
2568 for (j = 0; j < 2; j++) {
2569 u8 failmask;
2570 u8 expected_failmask;
2571 char reg1b3;
2572
2573 reg1b3 = (j == 1) + 4;
2574 reg1b3 =
2575 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2576 write_1d0(reg1b3, 0x1bb, 6, 1);
2577 write_1d0(reg1b3, 0x1b3, 6, 1);
2578 write_1d0(reg1b3, 0x1a3, 6, 1);
2579
2580 flip = !flip;
2581 write_testing(info, totalrank, flip);
2582 failmask =
2583 check_testing(info, totalrank,
2584 flip);
2585 expected_failmask =
2586 j == 0 ? 0x00 : 0xff;
2587 if (failmask != expected_failmask)
2588 goto fail;
2589 }
2590 }
2591 totalrank++;
2592 }
2593 }
2594
2595 set_178(info->cached_training->reg178_center);
2596 if (info->use_ecc)
2597 set_ecc(1);
2598 write_training_data(info);
2599 write_1d0(0, 322, 3, 1);
2600 info->training = *info->cached_training;
2601
2602 write_1d0(0, 0x1bb, 6, 1);
2603 write_1d0(0, 0x1b3, 6, 1);
2604 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002605 mchbar_write8(0x243, saved_243[0]);
2606 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002607
2608 return 1;
2609
2610fail:
2611 FOR_POPULATED_RANKS {
2612 write_500_timings_type(info, channel, slot, rank, 1);
2613 write_500_timings_type(info, channel, slot, rank, 2);
2614 write_500_timings_type(info, channel, slot, rank, 3);
2615 }
2616
2617 write_1d0(0, 0x1bb, 6, 1);
2618 write_1d0(0, 0x1b3, 6, 1);
2619 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002620 mchbar_write8(0x243, saved_243[0]);
2621 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002622
2623 return 0;
2624}
2625
2626static void do_ram_training(struct raminfo *info)
2627{
2628 u8 saved_243[2];
2629 int totalrank = 0;
2630 u8 reg_178;
2631 int niter;
2632
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002633 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002634 int lane, rank, slot, channel;
2635 u8 reg178_center;
2636
2637 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002638 saved_243[0] = mchbar_read8(0x243);
2639 saved_243[1] = mchbar_read8(0x643);
2640 mchbar_write8(0x243, saved_243[0] | 2);
2641 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002642 switch (info->clock_speed_index) {
2643 case 0:
2644 niter = 5;
2645 break;
2646 case 1:
2647 niter = 10;
2648 break;
2649 default:
2650 niter = 19;
2651 break;
2652 }
2653 set_ecc(0);
2654
2655 FOR_POPULATED_RANKS_BACKWARDS {
2656 int i;
2657
2658 write_500_timings_type(info, channel, slot, rank, 0);
2659
2660 write_testing(info, totalrank, 0);
2661 for (i = 0; i < niter; i++) {
2662 write_testing_type2(info, totalrank, 2, i, 0);
2663 write_testing_type2(info, totalrank, 3, i, 1);
2664 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002665 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002666 totalrank++;
2667 }
2668
2669 if (reg178_min[info->clock_speed_index] <
2670 reg178_max[info->clock_speed_index])
2671 memset(timings[reg178_min[info->clock_speed_index]], 0,
2672 sizeof(timings[0]) *
2673 (reg178_max[info->clock_speed_index] -
2674 reg178_min[info->clock_speed_index]));
2675 for (reg_178 = reg178_min[info->clock_speed_index];
2676 reg_178 < reg178_max[info->clock_speed_index];
2677 reg_178 += reg178_step[info->clock_speed_index]) {
2678 totalrank = 0;
2679 set_178(reg_178);
2680 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2681 for (slot = 0; slot < NUM_SLOTS; slot++)
2682 for (rank = 0; rank < NUM_RANKS; rank++) {
2683 memset(&timings[reg_178][channel][slot]
2684 [rank][0].smallest, 0, 16);
2685 if (info->
2686 populated_ranks[channel][slot]
2687 [rank]) {
2688 train_ram_at_178(info, channel,
2689 slot, rank,
2690 totalrank,
2691 reg_178, 1,
2692 niter,
2693 timings);
2694 totalrank++;
2695 }
2696 }
2697 }
2698
2699 reg178_center = choose_reg178(info, timings);
2700
2701 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2702 info->training.timing_bounds[0][channel][slot][rank][lane].
2703 smallest =
2704 timings[info->training.
2705 reg178_smallest][channel][slot][rank][lane].
2706 smallest;
2707 info->training.timing_bounds[0][channel][slot][rank][lane].
2708 largest =
2709 timings[info->training.
2710 reg178_smallest][channel][slot][rank][lane].largest;
2711 info->training.timing_bounds[1][channel][slot][rank][lane].
2712 smallest =
2713 timings[info->training.
2714 reg178_largest][channel][slot][rank][lane].smallest;
2715 info->training.timing_bounds[1][channel][slot][rank][lane].
2716 largest =
2717 timings[info->training.
2718 reg178_largest][channel][slot][rank][lane].largest;
2719 info->training.timing_offset[channel][slot][rank][lane] =
2720 info->training.lane_timings[1][channel][slot][rank][lane]
2721 -
2722 info->training.lane_timings[0][channel][slot][rank][lane] +
2723 64;
2724 }
2725
2726 if (info->silicon_revision == 1
2727 && (info->
2728 populated_ranks_mask[1] ^ (info->
2729 populated_ranks_mask[1] >> 2)) & 1) {
2730 int ranks_after_channel1;
2731
2732 totalrank = 0;
2733 for (reg_178 = reg178_center - 18;
2734 reg_178 <= reg178_center + 18; reg_178 += 18) {
2735 totalrank = 0;
2736 set_178(reg_178);
2737 for (slot = 0; slot < NUM_SLOTS; slot++)
2738 for (rank = 0; rank < NUM_RANKS; rank++) {
2739 if (info->
2740 populated_ranks[1][slot][rank]) {
2741 train_ram_at_178(info, 1, slot,
2742 rank,
2743 totalrank,
2744 reg_178, 0,
2745 niter,
2746 timings);
2747 totalrank++;
2748 }
2749 }
2750 }
2751 ranks_after_channel1 = totalrank;
2752
2753 for (reg_178 = reg178_center - 12;
2754 reg_178 <= reg178_center + 12; reg_178 += 12) {
2755 totalrank = ranks_after_channel1;
2756 set_178(reg_178);
2757 for (slot = 0; slot < NUM_SLOTS; slot++)
2758 for (rank = 0; rank < NUM_RANKS; rank++)
2759 if (info->
2760 populated_ranks[0][slot][rank]) {
2761 train_ram_at_178(info, 0, slot,
2762 rank,
2763 totalrank,
2764 reg_178, 0,
2765 niter,
2766 timings);
2767 totalrank++;
2768 }
2769
2770 }
2771 } else {
2772 for (reg_178 = reg178_center - 12;
2773 reg_178 <= reg178_center + 12; reg_178 += 12) {
2774 totalrank = 0;
2775 set_178(reg_178);
2776 FOR_POPULATED_RANKS_BACKWARDS {
2777 train_ram_at_178(info, channel, slot, rank,
2778 totalrank, reg_178, 0, niter,
2779 timings);
2780 totalrank++;
2781 }
2782 }
2783 }
2784
2785 set_178(reg178_center);
2786 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2787 u16 tm0;
2788
2789 tm0 =
2790 choose_training(info, channel, slot, rank, lane, timings,
2791 reg178_center);
2792 write_500(info, channel, tm0,
2793 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2794 write_500(info, channel,
2795 tm0 +
2796 info->training.
2797 lane_timings[1][channel][slot][rank][lane] -
2798 info->training.
2799 lane_timings[0][channel][slot][rank][lane],
2800 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
2801 }
2802
2803 totalrank = 0;
2804 FOR_POPULATED_RANKS_BACKWARDS {
2805 try_timing_offsets(info, channel, slot, rank, totalrank);
2806 totalrank++;
2807 }
Angel Ponsdea722b2021-03-26 14:11:12 +01002808 mchbar_write8(0x243, saved_243[0]);
2809 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002810 write_1d0(0, 0x142, 3, 1);
2811 info->training.reg178_center = reg178_center;
2812}
2813
2814static void ram_training(struct raminfo *info)
2815{
2816 u16 saved_fc4;
2817
Angel Ponsdea722b2021-03-26 14:11:12 +01002818 saved_fc4 = mchbar_read16(0xfc4);
2819 mchbar_write16(0xfc4, 0xffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002820
2821 if (info->revision >= 8)
2822 read_4090(info);
2823
2824 if (!try_cached_training(info))
2825 do_ram_training(info);
2826 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
2827 && info->clock_speed_index < 2)
2828 set_10b(info, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002829 mchbar_write16(0xfc4, saved_fc4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002830}
2831
Angel Pons7a87c922021-01-15 22:50:41 +01002832u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002833{
2834 int slot, rank, lane;
2835 u16 ret = 0;
2836
Angel Ponsdea722b2021-03-26 14:11:12 +01002837 if ((mchbar_read8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002838 return 384;
2839
2840 if (info->revision < 8)
2841 return 256;
2842
2843 for (slot = 0; slot < NUM_SLOTS; slot++)
2844 for (rank = 0; rank < NUM_RANKS; rank++)
2845 if (info->populated_ranks[channel][slot][rank])
2846 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002847 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002848 get_timing_register_addr
2849 (lane, 0, slot,
2850 rank), 9));
2851 return ret;
2852}
2853
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002854static void dmi_setup(void)
2855{
Angel Ponsdea722b2021-03-26 14:11:12 +01002856 gav(dmibar_read8(0x254));
2857 dmibar_write8(0x254, 1 << 0);
2858 dmibar_write16(0x1b8, 0x18f2);
2859 mchbar_clrsetbits16(0x48, ~0, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002860
Angel Ponsdea722b2021-03-26 14:11:12 +01002861 dmibar_setbits32(0xd68, 1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002862
2863 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
2864 DEFAULT_GPIOBASE | 0x38);
2865 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
2866}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002867
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002868void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002869{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002870 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02002871 u16 ggc;
2872 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002873
Angel Ponsdea722b2021-03-26 14:11:12 +01002874 x2ca8 = mchbar_read8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002875 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
2876 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Angel Ponsdea722b2021-03-26 14:11:12 +01002877 mchbar_write8(0x2ca8, 0);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02002878 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002879 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002880
2881 dmi_setup();
2882
Angel Ponsdea722b2021-03-26 14:11:12 +01002883 mchbar_write16(0x1170, 0xa880);
2884 mchbar_write8(0x11c1, 1 << 0);
2885 mchbar_write16(0x1170, 0xb880);
2886 mchbar_clrsetbits8(0x1210, ~0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002887
Angel Pons88dcb312021-04-26 17:10:28 +02002888 gfxsize = get_uint_option("gfx_uma_size", 0); /* 0 for 32MB */
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02002889
2890 ggc = 0xb00 | ((gfxsize + 5) << 4);
2891
Angel Pons16fe1e02020-07-22 16:12:33 +02002892 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002893
2894 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02002895 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002896
2897 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +01002898 mchbar_write8(0x2c30, 1 << 5);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002899 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Angel Ponsdea722b2021-03-26 14:11:12 +01002900 mchbar_setbits16(0x2c30, 1 << 9);
2901 mchbar_write16(0x2c32, 0x434);
2902 mchbar_clrsetbits32(0x2c44, ~0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02002903 pci_read_config8(GMA, MSAC); // = 0x2
2904 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01002905 RCBA8(0x2318);
2906 RCBA8(0x2318) = 0x47;
2907 RCBA8(0x2320);
2908 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002909 }
2910
Angel Ponsdea722b2021-03-26 14:11:12 +01002911 mchbar_clrsetbits32(0x30, ~0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002912
Angel Pons16fe1e02020-07-22 16:12:33 +02002913 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01002914 gav(RCBA32(0x3428));
2915 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002916}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002917
Angel Pons26681912021-01-15 21:36:28 +01002918static u8 get_bits_420(const u32 reg32)
2919{
2920 u8 val = 0;
2921 val |= (reg32 >> 4) & (1 << 0);
2922 val |= (reg32 >> 2) & (1 << 1);
2923 val |= (reg32 >> 0) & (1 << 2);
2924 return val;
2925}
2926
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002927void raminit(const int s3resume, const u8 *spd_addrmap)
2928{
Martin Roth468d02c2019-10-23 21:44:42 -06002929 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002930 struct raminfo info;
2931 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02002932 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01002933
Angel Ponsdea722b2021-03-26 14:11:12 +01002934 x2ca8 = mchbar_read8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02002935
2936 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
2937
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002938 memset(&info, 0x5a, sizeof(info));
2939
2940 info.last_500_command[0] = 0;
2941 info.last_500_command[1] = 0;
2942
2943 info.fsb_frequency = 135 * 2;
2944 info.board_lane_delay[0] = 0x14;
2945 info.board_lane_delay[1] = 0x07;
2946 info.board_lane_delay[2] = 0x07;
2947 info.board_lane_delay[3] = 0x08;
2948 info.board_lane_delay[4] = 0x56;
2949 info.board_lane_delay[5] = 0x04;
2950 info.board_lane_delay[6] = 0x04;
2951 info.board_lane_delay[7] = 0x05;
2952 info.board_lane_delay[8] = 0x10;
2953
2954 info.training.reg_178 = 0;
2955 info.training.reg_10b = 0;
2956
Angel Ponsa3868292021-01-15 22:10:13 +01002957 /* Wait for some bit, maybe TXT clear. */
2958 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
2959 ;
2960
2961 /* Wait for ME to be ready */
Nico Huber56441322021-04-23 15:23:14 +00002962 intel_early_me_init();
2963 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002964
2965 /* before SPD */
2966 timestamp_add_now(101);
2967
Felix Held29a9c072018-07-29 01:34:45 +02002968 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002969 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
2970
2971 info.use_ecc = 1;
2972 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01002973 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002974 int v;
2975 int try;
2976 int addr;
2977 const u8 useful_addresses[] = {
2978 DEVICE_TYPE,
2979 MODULE_TYPE,
2980 DENSITY,
2981 RANKS_AND_DQ,
2982 MEMORY_BUS_WIDTH,
2983 TIMEBASE_DIVIDEND,
2984 TIMEBASE_DIVISOR,
2985 CYCLETIME,
2986 CAS_LATENCIES_LSB,
2987 CAS_LATENCIES_MSB,
2988 CAS_LATENCY_TIME,
2989 0x11, 0x12, 0x13, 0x14, 0x15,
2990 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
2991 0x1c, 0x1d,
2992 THERMAL_AND_REFRESH,
2993 0x20,
2994 REFERENCE_RAW_CARD_USED,
2995 RANK1_ADDRESS_MAPPING,
2996 0x75, 0x76, 0x77, 0x78,
2997 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
2998 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
2999 0x85, 0x86, 0x87, 0x88,
3000 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3001 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3002 0x95
3003 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003004 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003005 continue;
3006 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003007 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003008 DEVICE_TYPE);
3009 if (v >= 0)
3010 break;
3011 }
3012 if (v < 0)
3013 continue;
3014 for (addr = 0;
3015 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003016 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003017 gav(info.
3018 spd[channel][0][useful_addresses
3019 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003020 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003021 useful_addresses
3022 [addr]));
3023 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3024 die("Only DDR3 is supported");
3025
3026 v = info.spd[channel][0][RANKS_AND_DQ];
3027 info.populated_ranks[channel][0][0] = 1;
3028 info.populated_ranks[channel][0][1] =
3029 ((v >> 3) & 7);
3030 if (((v >> 3) & 7) > 1)
3031 die("At most 2 ranks are supported");
3032 if ((v & 7) == 0 || (v & 7) > 2)
3033 die("Only x8 and x16 modules are supported");
3034 if ((info.
3035 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3036 && (info.
3037 spd[channel][slot][MODULE_TYPE] & 0xF)
3038 != 3)
3039 die("Registered memory is not supported");
3040 info.is_x16_module[channel][0] = (v & 7) - 1;
3041 info.density[channel][slot] =
3042 info.spd[channel][slot][DENSITY] & 0xF;
3043 if (!
3044 (info.
3045 spd[channel][slot][MEMORY_BUS_WIDTH] &
3046 0x18))
3047 info.use_ecc = 0;
3048 }
3049
3050 gav(0x55);
3051
3052 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3053 int v = 0;
3054 for (slot = 0; slot < NUM_SLOTS; slot++)
3055 for (rank = 0; rank < NUM_RANKS; rank++)
3056 v |= info.
3057 populated_ranks[channel][slot][rank]
3058 << (2 * slot + rank);
3059 info.populated_ranks_mask[channel] = v;
3060 }
3061
3062 gav(0x55);
3063
Angel Pons16fe1e02020-07-22 16:12:33 +02003064 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003065 }
3066
3067 /* after SPD */
3068 timestamp_add_now(102);
3069
Angel Ponsdea722b2021-03-26 14:11:12 +01003070 mchbar_clrbits8(0x2ca8, 1 << 1 | 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003071
3072 collect_system_info(&info);
3073 calculate_timings(&info);
3074
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003075 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003076 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003077 if (x2ca8 == 0 && (reg8 & 0x80)) {
3078 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3079 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3080 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3081 */
3082
3083 /* Clear bit7. */
3084
3085 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3086 (reg8 & ~(1 << 7)));
3087
3088 printk(BIOS_INFO,
3089 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003090 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003091 }
3092 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003093
3094 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003095 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3096 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003097
3098 compute_derived_timings(&info);
3099
Angel Pons56823f52021-01-16 11:27:33 +01003100 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003101
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003102 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003103
Angel Pons7a87c922021-01-15 22:50:41 +01003104 if (x2ca8 == 0)
3105 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003106
Angel Ponsdea722b2021-03-26 14:11:12 +01003107 mchbar_setbits32(0x2c80, 1 << 24);
3108 mchbar_write32(0x1804, mchbar_read32(0x1c04) & ~(1 << 27));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003109
Angel Ponsdea722b2021-03-26 14:11:12 +01003110 mchbar_read8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003111
3112 if (x2ca8 == 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003113 mchbar_clrbits8(0x2ca8, 3);
3114 mchbar_write8(0x2ca8, mchbar_read8(0x2ca8) + 4); // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003115 /* This issues a CPU reset without resetting the platform */
3116 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003117 /* Write back the S3 state to PM1_CNT to let the reset CPU
3118 know it also needs to take the s3 path. */
3119 if (s3resume)
3120 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3121 | (SLP_TYP_S3 << 10));
Angel Ponsdea722b2021-03-26 14:11:12 +01003122 mchbar_setbits32(0x1af0, 1 << 4);
Patrick Georgi546953c2014-11-29 10:38:17 +01003123 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003124 }
Angel Pons7a87c922021-01-15 22:50:41 +01003125
Angel Ponsdea722b2021-03-26 14:11:12 +01003126 mchbar_clrbits8(0x2ca8, 0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003127
Angel Ponsdea722b2021-03-26 14:11:12 +01003128 mchbar_clrbits32(0x2c80, 1 << 24);
Angel Ponsc627dc92020-09-22 17:06:44 +02003129
Angel Pons9addda32020-07-22 18:37:32 +02003130 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003131
3132 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003133 u8 x2c20 = (mchbar_read16(0x2c20) >> 8) & 3;
3134 u16 x2c10 = mchbar_read16(0x2c10);
3135 u16 value = mchbar_read16(0x2c00);
Angel Ponsc627dc92020-09-22 17:06:44 +02003136 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3137 value |= (1 << 7);
3138 else
3139 value &= ~(1 << 0);
3140
Angel Ponsdea722b2021-03-26 14:11:12 +01003141 mchbar_write16(0x2c00, value);
Angel Ponsc627dc92020-09-22 17:06:44 +02003142 }
3143
3144 udelay(1000); // !!!!
3145
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003146 write_1d0(0, 0x33d, 0, 0);
3147 write_500(&info, 0, 0, 0xb61, 0, 0);
3148 write_500(&info, 1, 0, 0xb61, 0, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01003149 mchbar_write32(0x1a30, 0);
3150 mchbar_write32(0x1a34, 0);
3151 mchbar_write16(0x614, 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3152 (info.populated_ranks[0][0][0] * 0xa0));
3153 mchbar_write16(0x616, 0x26a);
3154 mchbar_write32(0x134, 0x856000);
3155 mchbar_write32(0x160, 0x5ffffff);
3156 mchbar_clrsetbits32(0x114, ~0, 0xc2024440); // !!!!
3157 mchbar_clrsetbits32(0x118, ~0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003158 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003159 mchbar_write32(0x260 + (channel << 10), 0x30809ff |
3160 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003161 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003162 mchbar_write16(0x31c + (channel << 10), 0x101);
3163 mchbar_write16(0x360 + (channel << 10), 0x909);
3164 mchbar_write16(0x3a4 + (channel << 10), 0x101);
3165 mchbar_write16(0x3e8 + (channel << 10), 0x101);
3166 mchbar_write32(0x320 + (channel << 10), 0x29002900);
3167 mchbar_write32(0x324 + (channel << 10), 0);
3168 mchbar_write32(0x368 + (channel << 10), 0x32003200);
3169 mchbar_write16(0x352 + (channel << 10), 0x505);
3170 mchbar_write16(0x354 + (channel << 10), 0x3c3c);
3171 mchbar_write16(0x356 + (channel << 10), 0x1040);
3172 mchbar_write16(0x39a + (channel << 10), 0x73e4);
3173 mchbar_write16(0x3de + (channel << 10), 0x77ed);
3174 mchbar_write16(0x422 + (channel << 10), 0x1040);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003175 }
3176
3177 write_1d0(0x4, 0x151, 4, 1);
3178 write_1d0(0, 0x142, 3, 1);
3179 rdmsr(0x1ac); // !!!!
3180 write_500(&info, 1, 1, 0x6b3, 4, 1);
3181 write_500(&info, 1, 1, 0x6cf, 4, 1);
3182
Angel Pons244f4552021-01-15 20:41:36 +01003183 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003184
3185 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3186 populated_ranks[0]
3187 [0][0]) << 0),
3188 0x1d1, 3, 1);
3189 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003190 mchbar_write16(0x38e + (channel << 10), 0x5f5f);
3191 mchbar_write16(0x3d2 + (channel << 10), 0x5f5f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003192 }
3193
3194 set_334(0);
3195
3196 program_base_timings(&info);
3197
Angel Ponsdea722b2021-03-26 14:11:12 +01003198 mchbar_setbits8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003199
3200 write_1d0(0x2, 0x1d5, 2, 1);
3201 write_1d0(0x20, 0x166, 7, 1);
3202 write_1d0(0x0, 0xeb, 3, 1);
3203 write_1d0(0x0, 0xf3, 6, 1);
3204
Angel Pons3d357562021-01-16 14:46:45 +01003205 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3206 u8 a = 0;
3207 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3208 a = 3;
3209 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3210 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003211
Angel Pons3d357562021-01-16 14:46:45 +01003212 for (lane = 0; lane < 9; lane++) {
3213 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3214 rmw_500(&info, channel, addr, 6, 0xf, a);
3215 }
3216 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003217
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003218 if (s3resume) {
3219 if (info.cached_training == NULL) {
3220 u32 reg32;
3221 printk(BIOS_ERR,
3222 "Couldn't find training data. Rebooting\n");
3223 reg32 = inl(DEFAULT_PMBASE + 0x04);
3224 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003225 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003226 }
3227 int tm;
3228 info.training = *info.cached_training;
3229 for (tm = 0; tm < 4; tm++)
3230 for (channel = 0; channel < NUM_CHANNELS; channel++)
3231 for (slot = 0; slot < NUM_SLOTS; slot++)
3232 for (rank = 0; rank < NUM_RANKS; rank++)
3233 for (lane = 0; lane < 9; lane++)
3234 write_500(&info,
3235 channel,
3236 info.training.
3237 lane_timings
3238 [tm][channel]
3239 [slot][rank]
3240 [lane],
3241 get_timing_register_addr
3242 (lane, tm,
3243 slot, rank),
3244 9, 0);
3245 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3246 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3247 }
3248
Angel Ponsdea722b2021-03-26 14:11:12 +01003249 mchbar_clrsetbits32(0x1f4, ~0, 1 << 17); // !!!!
3250 mchbar_write32(0x1f0, 0x1d000200);
3251 mchbar_setbits8(0x1f0, 1 << 0);
3252 while (mchbar_read8(0x1f0) & 1)
Angel Ponsc627dc92020-09-22 17:06:44 +02003253 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003254
3255 program_board_delay(&info);
3256
Angel Ponsdea722b2021-03-26 14:11:12 +01003257 mchbar_write8(0x5ff, 0);
3258 mchbar_write8(0x5ff, 1 << 7);
3259 mchbar_write8(0x5f4, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003260
Angel Ponsdea722b2021-03-26 14:11:12 +01003261 mchbar_clrbits32(0x130, 1 << 1); // | 2 when ?
3262 while (mchbar_read32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003263 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003264
3265 rmw_1d0(0x14b, 0x47, 0x30, 7);
3266 rmw_1d0(0xd6, 0x38, 7, 6);
3267 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003268
3269 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003270 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003271
Angel Ponsc627dc92020-09-22 17:06:44 +02003272 rmw_1d0(0x116, 0xe, 0, 4);
3273 rmw_1d0(0xae, 0x3e, 0, 6);
3274 rmw_1d0(0x300, 0x3e, 0, 6);
Angel Ponsdea722b2021-03-26 14:11:12 +01003275 mchbar_clrbits16(0x356, 1 << 15);
3276 mchbar_clrbits16(0x756, 1 << 15);
3277 mchbar_clrbits32(0x140, 7 << 24);
3278 mchbar_clrbits32(0x138, 7 << 24);
3279 mchbar_write32(0x130, 0x31111301);
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003280 /* Wait until REG130b0 is 1. */
Angel Ponsdea722b2021-03-26 14:11:12 +01003281 while (mchbar_read32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003282 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003283
Angel Pons26681912021-01-15 21:36:28 +01003284 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003285 {
Angel Pons26681912021-01-15 21:36:28 +01003286 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3287 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3288 value_a1 = val_xa1;
3289 rmw_1d0(0x320, 0x38, val_2f3, 6);
3290 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3291 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003292 }
3293
3294 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003295 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003296
Angel Pons244f4552021-01-15 20:41:36 +01003297 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003298 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003299 if ((mchbar_read32(0x144) & 0x1f) < 0x13)
Angel Pons26681912021-01-15 21:36:28 +01003300 value_a1 += 2;
3301 else
3302 value_a1 += 1;
3303
3304 if (value_a1 > 7)
3305 value_a1 = 7;
3306
3307 write_1d0(2, 0xae, 6, 1);
3308 write_1d0(2, 0x300, 6, 1);
3309 write_1d0(value_a1, 0x121, 3, 1);
3310 rmw_1d0(0xd6, 0x38, 4, 6);
3311 rmw_1d0(0x328, 0x38, 4, 6);
3312 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003313
3314 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003315 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003316
Angel Ponsdea722b2021-03-26 14:11:12 +01003317 mchbar_write32(0x130, 0x11111301 | info.populated_ranks[1][0][0] << 30 |
3318 info.populated_ranks[0][0][0] << 29);
3319 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003320 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003321
3322 {
Angel Pons26681912021-01-15 21:36:28 +01003323 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003324 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3325 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003326 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003327 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003328
3329 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003330 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003331
3332 set_334(1);
3333
Angel Ponsdea722b2021-03-26 14:11:12 +01003334 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003335
3336 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3337 write_500(&info, channel,
3338 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3339 1);
3340 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3341 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003342 mchbar_clrsetbits32(0x2d0, ~0xff0c01ff, 0x200000);
3343 mchbar_write16(0x6c0, 0x14a0);
3344 mchbar_clrsetbits32(0x6d0, ~0xff0000ff, 0x8000);
3345 mchbar_write16(0x232, 1 << 3);
Felix Held04be2dd2018-07-29 04:53:22 +02003346 /* 0x40004 or 0 depending on ? */
Angel Ponsdea722b2021-03-26 14:11:12 +01003347 mchbar_clrsetbits32(0x234, 0x40004, 0x40004);
3348 mchbar_clrsetbits32(0x34, 0x7, 5);
3349 mchbar_write32(0x128, 0x2150d05);
3350 mchbar_write8(0x12c, 0x1f);
3351 mchbar_write8(0x12d, 0x56);
3352 mchbar_write8(0x12e, 0x31);
3353 mchbar_write8(0x12f, 0);
3354 mchbar_write8(0x271, 1 << 1);
3355 mchbar_write8(0x671, 1 << 1);
3356 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003357 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003358 mchbar_write32(0x294 + (channel << 10),
3359 (info.populated_ranks_mask[channel] & 3) << 16);
3360 mchbar_clrsetbits32(0x134, ~0xfc01ffff, 0x10000);
3361 mchbar_clrsetbits32(0x134, ~0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003362 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003363 mchbar_clrsetbits32(0x260 + (channel << 10), 0xf << 20, 1 << 27 |
3364 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003365
3366 if (!s3resume)
3367 jedec_init(&info);
3368
3369 int totalrank = 0;
3370 for (channel = 0; channel < NUM_CHANNELS; channel++)
3371 for (slot = 0; slot < NUM_SLOTS; slot++)
3372 for (rank = 0; rank < NUM_RANKS; rank++)
3373 if (info.populated_ranks[channel][slot][rank]) {
3374 jedec_read(&info, channel, slot, rank,
3375 totalrank, 0xa, 0x400);
3376 totalrank++;
3377 }
3378
Angel Ponsdea722b2021-03-26 14:11:12 +01003379 mchbar_write8(0x12c, 0x9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003380
Angel Ponsdea722b2021-03-26 14:11:12 +01003381 mchbar_clrsetbits8(0x271, 0x3e, 0x0e);
3382 mchbar_clrsetbits8(0x671, 0x3e, 0x0e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003383
3384 if (!s3resume) {
3385 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003386 mchbar_write32(0x294 + (channel << 10),
3387 (info.populated_ranks_mask[channel] & 3) << 16);
3388 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003389 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003390 info.populated_ranks[channel][0][1] << 5);
3391 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003392 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003393 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003394
3395 {
3396 u8 a, b;
Angel Ponsdea722b2021-03-26 14:11:12 +01003397 a = mchbar_read8(0x243);
3398 b = mchbar_read8(0x643);
3399 mchbar_write8(0x243, a | 2);
3400 mchbar_write8(0x643, b | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003401 }
3402
3403 write_1d0(7, 0x19b, 3, 1);
3404 write_1d0(7, 0x1c0, 3, 1);
3405 write_1d0(4, 0x1c6, 4, 1);
3406 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003407 rmw_1d0(0x151, 0xf, 0x4, 4);
Angel Ponsdea722b2021-03-26 14:11:12 +01003408 mchbar_write32(0x584, 0xfffff);
3409 mchbar_write32(0x984, 0xfffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003410
3411 for (channel = 0; channel < NUM_CHANNELS; channel++)
3412 for (slot = 0; slot < NUM_SLOTS; slot++)
3413 for (rank = 0; rank < NUM_RANKS; rank++)
3414 if (info.
3415 populated_ranks[channel][slot]
3416 [rank])
3417 config_rank(&info, s3resume,
3418 channel, slot,
3419 rank);
3420
Angel Ponsdea722b2021-03-26 14:11:12 +01003421 mchbar_write8(0x243, 1);
3422 mchbar_write8(0x643, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003423 }
3424
3425 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003426 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003427 write_26c(0, 0x820);
3428 write_26c(1, 0x820);
Angel Ponsdea722b2021-03-26 14:11:12 +01003429 mchbar_setbits32(0x130, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003430 /* end */
3431
3432 if (s3resume) {
3433 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003434 mchbar_write32(0x294 + (channel << 10),
3435 (info.populated_ranks_mask[channel] & 3) << 16);
3436 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003437 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003438 info.populated_ranks[channel][0][1] << 5);
3439 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003440 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003441 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003442 }
3443
Angel Ponsdea722b2021-03-26 14:11:12 +01003444 mchbar_clrbits32(0xfa4, 1 << 24 | 1 << 1);
3445 mchbar_write32(0xfb0, 0x2000e019);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003446
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003447 /* Before training. */
3448 timestamp_add_now(103);
3449
3450 if (!s3resume)
3451 ram_training(&info);
3452
3453 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003454 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003455
3456 dump_timings(&info);
3457
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003458 program_modules_memory_map(&info, 0);
3459 program_total_memory_map(&info);
3460
3461 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Angel Ponsdea722b2021-03-26 14:11:12 +01003462 mchbar_write8(0x111, 0 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003463 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Angel Ponsdea722b2021-03-26 14:11:12 +01003464 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003465 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Angel Ponsdea722b2021-03-26 14:11:12 +01003466 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003467 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003468 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003469
Angel Ponsdea722b2021-03-26 14:11:12 +01003470 mchbar_clrbits32(0xfac, 1 << 31);
3471 mchbar_write32(0xfb4, 0x4800);
3472 mchbar_write32(0xfb8, (info.revision < 8) ? 0x20 : 0x0);
3473 mchbar_write32(0xe94, 0x7ffff);
3474 mchbar_write32(0xfc0, 0x80002040);
3475 mchbar_write32(0xfc4, 0x701246);
3476 mchbar_clrbits8(0xfc8, 0x70);
3477 mchbar_setbits32(0xe5c, 1 << 24);
3478 mchbar_clrsetbits32(0x1a70, 3 << 20, 2 << 20);
3479 mchbar_write32(0x50, 0x700b0);
3480 mchbar_write32(0x3c, 0x10);
3481 mchbar_clrsetbits8(0x1aa8, 0x3f, 0xa);
3482 mchbar_setbits8(0xff4, 1 << 1);
3483 mchbar_clrsetbits32(0xff8, 0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003484
Angel Ponsdea722b2021-03-26 14:11:12 +01003485 mchbar_write32(0xd00, IOMMU_BASE2 | 1);
3486 mchbar_write32(0xd40, IOMMU_BASE1 | 1);
3487 mchbar_write32(0xdc0, IOMMU_BASE4 | 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003489 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3490 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3491 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003492
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493 {
3494 u32 eax;
3495
3496 eax = info.fsb_frequency / 9;
Angel Ponsdea722b2021-03-26 14:11:12 +01003497 mchbar_clrsetbits32(0xfcc, 0x3ffff,
Felix Held04be2dd2018-07-29 04:53:22 +02003498 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003499 mchbar_write32(0x20, 0x33001);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003500 }
3501
3502 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003503 mchbar_clrbits32(0x220 + (channel << 10), 0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 if (info.max_slots_used_in_channel == 1)
Angel Ponsdea722b2021-03-26 14:11:12 +01003505 mchbar_setbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003506 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003507 mchbar_clrbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003508
Angel Ponsdea722b2021-03-26 14:11:12 +01003509 mchbar_setbits8(0x241 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003510
Felix Held04be2dd2018-07-29 04:53:22 +02003511 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003512 || info.silicon_revision == 3))
Angel Ponsdea722b2021-03-26 14:11:12 +01003513 mchbar_setbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003515 mchbar_clrbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516 }
3517
Angel Ponsdea722b2021-03-26 14:11:12 +01003518 mchbar_setbits32(0x115, 1 << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003519
3520 {
3521 u8 al;
3522 al = 0xd;
3523 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3524 al += 2;
3525 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Angel Ponsdea722b2021-03-26 14:11:12 +01003526 mchbar_write32(0x210, al << 16 | 0x20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003527 }
3528
3529 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003530 mchbar_write32(0x288 + (channel << 10), 0x70605040);
3531 mchbar_write32(0x28c + (channel << 10), 0xfffec080);
3532 mchbar_write32(0x290 + (channel << 10), 0x282091c |
3533 (info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003534 }
3535 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003536 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003537 reg1c = epbar_read32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003538 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003539 epbar_write32(EPVC1RCAP, reg1c); // OK
3540 mchbar_read8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003541 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Angel Ponsdea722b2021-03-26 14:11:12 +01003542 mchbar_setbits8(0x1210, 1 << 1);
3543 mchbar_write32(0x1200, 0x8800440);
3544 mchbar_write32(0x1204, 0x53ff0453);
3545 mchbar_write32(0x1208, 0x19002043);
3546 mchbar_write16(0x1214, 0x320);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003547
3548 if (info.revision == 0x10 || info.revision == 0x11) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003549 mchbar_write16(0x1214, 0x220);
3550 mchbar_setbits8(0x1210, 1 << 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003551 }
3552
Angel Ponsdea722b2021-03-26 14:11:12 +01003553 mchbar_setbits8(0x1214, 1 << 2);
3554 mchbar_write8(0x120c, 1);
3555 mchbar_write8(0x1218, 3);
3556 mchbar_write8(0x121a, 3);
3557 mchbar_write8(0x121c, 3);
3558 mchbar_write16(0xc14, 0);
3559 mchbar_write16(0xc20, 0);
3560 mchbar_write32(0x1c, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003561
3562 /* revision dependent here. */
3563
Angel Ponsdea722b2021-03-26 14:11:12 +01003564 mchbar_setbits16(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003565
3566 if (info.uma_enabled)
Angel Ponsdea722b2021-03-26 14:11:12 +01003567 mchbar_setbits32(0x11f4, 1 << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003568
Angel Ponsdea722b2021-03-26 14:11:12 +01003569 mchbar_setbits16(0x1230, 1 << 15);
3570 mchbar_setbits8(0x1214, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003571
3572 u8 bl, ebpb;
3573 u16 reg_1020;
3574
Angel Ponsdea722b2021-03-26 14:11:12 +01003575 reg_1020 = mchbar_read32(0x1020); // = 0x6c733c // OK
3576 mchbar_write8(0x1070, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003577
Angel Ponsdea722b2021-03-26 14:11:12 +01003578 mchbar_write32(0x1000, 0x100);
3579 mchbar_write8(0x1007, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003580
3581 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003582 mchbar_write16(0x1018, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003583 bl = reg_1020 >> 8;
3584 ebpb = reg_1020 & 0xff;
3585 } else {
3586 ebpb = 0;
3587 bl = 8;
3588 }
3589
3590 rdmsr(0x1a2);
3591
Angel Ponsdea722b2021-03-26 14:11:12 +01003592 mchbar_write32(0x1014, 0xffffffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003593
Angel Ponsdea722b2021-03-26 14:11:12 +01003594 mchbar_write32(0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * !!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595
Angel Ponsdea722b2021-03-26 14:11:12 +01003596 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003597
Angel Ponsdea722b2021-03-26 14:11:12 +01003598 mchbar_clrsetbits8(0x123e, 0xf0, 0x60);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003599 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003600 mchbar_clrsetbits32(0x123c, 0xf << 20, 0x6 << 20);
3601 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003602 }
3603
3604 setup_heci_uma(&info);
3605
3606 if (info.uma_enabled) {
3607 u16 ax;
Angel Ponsdea722b2021-03-26 14:11:12 +01003608 mchbar_setbits32(0x11b0, 1 << 14);
3609 mchbar_setbits32(0x11b4, 1 << 14);
3610 mchbar_setbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611
Angel Ponsdea722b2021-03-26 14:11:12 +01003612 ax = mchbar_read16(0x1190) & 0xf00; // = 0x480a // OK
3613 mchbar_write16(0x1170, ax | (mchbar_read16(0x1170) & 0x107f) | 0x4080);
3614 mchbar_setbits16(0x1170, 1 << 12);
Felix Held04be2dd2018-07-29 04:53:22 +02003615
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003617
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618 u16 ecx;
Angel Ponsdea722b2021-03-26 14:11:12 +01003619 for (ecx = 0xffff; ecx && (mchbar_read16(0x1170) & (1 << 12)); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003620 ;
Angel Ponsdea722b2021-03-26 14:11:12 +01003621 mchbar_clrbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 }
3623
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003624 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3625 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 udelay(10000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003627 mchbar_write16(0x2ca8, 1 << 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629 udelay(1000);
3630 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003631 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3632
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003633 if (!s3resume)
3634 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003635 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003636 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003637 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003638
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003639 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003640 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003641 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642}