blob: 4d8fa1328ec83ca3a575377c3c8d987fe2b28b15 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010058#include <lib.h> /* Prototypes */
59
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010060typedef struct _u128 {
61 u64 lo;
62 u64 hi;
63} u128;
64
65static void read128(u32 addr, u64 * out)
66{
67 u128 ret;
68 u128 stor;
69 asm volatile ("movdqu %%xmm0, %0\n"
70 "movdqa (%2), %%xmm0\n"
71 "movdqu %%xmm0, %1\n"
72 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
73 out[0] = ret.lo;
74 out[1] = ret.hi;
75}
76
Angel Ponsc2d6f5f2020-12-11 23:48:51 +010077/*
78 * Ironlake memory I/O timings are located in scan chains, accessible
79 * through MCHBAR register groups. Each channel has a scan chain, and
80 * there's a global scan chain too. Each chain is broken into smaller
81 * sections of N bits, where N <= 32. Each section allows reading and
82 * writing a certain parameter. Each section contains N - 2 data bits
83 * and two additional bits: a Mask bit, and a Halt bit.
84 */
85
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010086/* OK */
87static void write_1d0(u32 val, u16 addr, int bits, int flag)
88{
Angel Ponsdea722b2021-03-26 14:11:12 +010089 mchbar_write32(0x1d0, 0);
90 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +020091 ;
Angel Ponsdea722b2021-03-26 14:11:12 +010092 mchbar_write32(0x1d4, (val & ((1 << bits) - 1)) | 2 << bits | flag << bits);
93 mchbar_write32(0x1d0, 1 << 30 | addr);
94 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +020095 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096}
97
98/* OK */
99static u16 read_1d0(u16 addr, int split)
100{
101 u32 val;
Angel Ponsdea722b2021-03-26 14:11:12 +0100102 mchbar_write32(0x1d0, 0);
103 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200104 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100105 mchbar_write32(0x1d0, 1 << 31 | (((mchbar_read8(0x246) >> 2) & 3) + 0x361 - addr));
106 while (mchbar_read32(0x1d0) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200107 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100108 val = mchbar_read32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100109 write_1d0(0, 0x33d, 0, 0);
110 write_1d0(0, 0x33d, 0, 0);
111 val &= ((1 << split) - 1);
112 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
113 return val;
114}
115
116static void sfence(void)
117{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100118 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100119}
120
121static inline u16 get_lane_offset(int slot, int rank, int lane)
122{
123 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
124 0x452 * (lane == 8);
125}
126
127static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
128{
129 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
130 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
131}
132
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100133static u32 gav_real(int line, u32 in)
134{
135 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
136 return in;
137}
138
139#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200140
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200141/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100142timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200143
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100144/* OK */
145static u16
146read_500(struct raminfo *info, int channel, u16 addr, int split)
147{
148 u32 val;
Angel Ponsdea722b2021-03-26 14:11:12 +0100149 info->last_500_command[channel] = 1 << 31;
150 mchbar_write32(0x500 + (channel << 10), 0);
151 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200152 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100153 mchbar_write32(0x500 + (channel << 10),
154 1 << 31 | (((mchbar_read8(0x246 + (channel << 10)) >> 2) & 3) + 0xb88 - addr));
155 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200156 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100157 val = mchbar_read32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100158 return val & ((1 << split) - 1);
159}
160
161/* OK */
162static void
163write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
164 int flag)
165{
Angel Ponsdea722b2021-03-26 14:11:12 +0100166 if (info->last_500_command[channel] == 1 << 31) {
167 info->last_500_command[channel] = 1 << 30;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100168 write_500(info, channel, 0, 0xb61, 0, 0);
169 }
Angel Ponsdea722b2021-03-26 14:11:12 +0100170 mchbar_write32(0x500 + (channel << 10), 0);
171 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200172 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100173 mchbar_write32(0x504 + (channel << 10),
174 (val & ((1 << bits) - 1)) | 2 << bits | flag << bits);
175 mchbar_write32(0x500 + (channel << 10), 1 << 30 | addr);
176 while (mchbar_read32(0x500 + (channel << 10)) & (1 << 23))
Felix Held04be2dd2018-07-29 04:53:22 +0200177 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100178}
179
Angel Ponsc10f8b22021-01-15 20:34:51 +0100180static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
181{
182 const u32 val = read_500(info, channel, addr, bits) & and;
183 write_500(info, channel, val | or, addr, bits, 1);
184}
185
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100186static int rw_test(int rank)
187{
188 const u32 mask = 0xf00fc33c;
189 int ok = 0xff;
190 int i;
191 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800192 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100193 sfence();
194 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800195 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196 sfence();
197 for (i = 0; i < 32; i++) {
198 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800199 write32p((rank << 28) | (i << 3), pat);
200 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100201 }
202 sfence();
203 for (i = 0; i < 32; i++) {
204 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
205 int j;
206 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800207 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100208 for (j = 0; j < 4; j++)
209 if (((val >> (j * 8)) & 0xff) != pat)
210 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800211 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100212 for (j = 0; j < 4; j++)
213 if (((val >> (j * 8)) & 0xff) != pat)
214 ok &= ~(16 << j);
215 }
216 sfence();
217 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800218 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100219 sfence();
220 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800221 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100222
223 return ok;
224}
225
226static void
227program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
228{
229 int lane;
230 for (lane = 0; lane < 8; lane++) {
231 write_500(info, channel,
232 base +
233 info->training.
234 lane_timings[2][channel][slot][rank][lane],
235 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
236 write_500(info, channel,
237 base +
238 info->training.
239 lane_timings[3][channel][slot][rank][lane],
240 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
241 }
242}
243
244static void write_26c(int channel, u16 si)
245{
Angel Ponsdea722b2021-03-26 14:11:12 +0100246 mchbar_write32(0x26c + (channel << 10), 0x03243f35);
247 mchbar_write32(0x268 + (channel << 10), 0xcfc00000 | si << 9);
248 mchbar_write16(0x2b9 + (channel << 10), si);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100249}
250
Angel Ponsc627dc92020-09-22 17:06:44 +0200251static void toggle_1d0_142_5ff(void)
252{
253 u32 reg32 = gav(read_1d0(0x142, 3));
254 if (reg32 & (1 << 1))
255 write_1d0(0, 0x142, 3, 1);
256
Angel Ponsdea722b2021-03-26 14:11:12 +0100257 mchbar_write8(0x5ff, 0);
258 mchbar_write8(0x5ff, 1 << 7);
Angel Ponsc627dc92020-09-22 17:06:44 +0200259 if (reg32 & (1 << 1))
260 write_1d0(0x2, 0x142, 3, 1);
261}
262
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100263static u32 get_580(int channel, u8 addr)
264{
265 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200266 toggle_1d0_142_5ff();
Angel Ponsdea722b2021-03-26 14:11:12 +0100267 mchbar_write32(0x580 + (channel << 10), 0x8493c012 | addr);
268 mchbar_setbits8(0x580 + (channel << 10), 1 << 0);
269 while (!((ret = mchbar_read32(0x580 + (channel << 10))) & (1 << 16)))
Felix Held04be2dd2018-07-29 04:53:22 +0200270 ;
Angel Ponsdea722b2021-03-26 14:11:12 +0100271 mchbar_clrbits8(0x580 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100272 return ret;
273}
274
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100275#define RANK_SHIFT 28
276#define CHANNEL_SHIFT 10
277
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278static void seq9(struct raminfo *info, int channel, int slot, int rank)
279{
280 int i, lane;
281
282 for (i = 0; i < 2; i++)
283 for (lane = 0; lane < 8; lane++)
284 write_500(info, channel,
285 info->training.lane_timings[i +
286 1][channel][slot]
287 [rank][lane], get_timing_register_addr(lane,
288 i + 1,
289 slot,
290 rank),
291 9, 0);
292
293 write_1d0(1, 0x103, 6, 1);
294 for (lane = 0; lane < 8; lane++)
295 write_500(info, channel,
296 info->training.
297 lane_timings[0][channel][slot][rank][lane],
298 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
299
300 for (i = 0; i < 2; i++) {
301 for (lane = 0; lane < 8; lane++)
302 write_500(info, channel,
303 info->training.lane_timings[i +
304 1][channel][slot]
305 [rank][lane], get_timing_register_addr(lane,
306 i + 1,
307 slot,
308 rank),
309 9, 0);
310 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
311 }
312
Angel Ponsc627dc92020-09-22 17:06:44 +0200313 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100314 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200315
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100316 for (lane = 0; lane < 8; lane++) {
317 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
318 info->training.lane_timings[2][channel][slot][rank][lane] =
319 read_500(info, channel,
320 get_timing_register_addr(lane, 2, slot, rank), 9);
321 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
322 info->training.lane_timings[3][channel][slot][rank][lane] =
323 info->training.lane_timings[2][channel][slot][rank][lane] +
324 0x20;
325 }
326}
327
328static int count_ranks_in_channel(struct raminfo *info, int channel)
329{
330 int slot, rank;
331 int res = 0;
332 for (slot = 0; slot < NUM_SLOTS; slot++)
333 for (rank = 0; rank < NUM_SLOTS; rank++)
334 res += info->populated_ranks[channel][slot][rank];
335 return res;
336}
337
338static void
339config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
340{
341 int add;
342
343 write_1d0(0, 0x178, 7, 1);
344 seq9(info, channel, slot, rank);
345 program_timings(info, 0x80, channel, slot, rank);
346
347 if (channel == 0)
348 add = count_ranks_in_channel(info, 1);
349 else
350 add = 0;
351 if (!s3resume)
352 gav(rw_test(rank + add));
353 program_timings(info, 0x00, channel, slot, rank);
354 if (!s3resume)
355 gav(rw_test(rank + add));
356 if (!s3resume)
357 gav(rw_test(rank + add));
358 write_1d0(0, 0x142, 3, 1);
359 write_1d0(0, 0x103, 6, 1);
360
361 gav(get_580(channel, 0xc | (rank << 5)));
362 gav(read_1d0(0x142, 3));
363
Angel Ponsdea722b2021-03-26 14:11:12 +0100364 mchbar_write8(0x5ff, 0);
365 mchbar_write8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100366}
367
Angel Ponsc10f8b22021-01-15 20:34:51 +0100368static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100369{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100370 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
371
372 val &= 1;
373 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
374 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100375}
376
377static void set_334(int zero)
378{
379 int j, k, channel;
380 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
381 u32 vd8[2][16];
382
383 for (channel = 0; channel < NUM_CHANNELS; channel++) {
384 for (j = 0; j < 4; j++) {
385 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
386 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
387 u16 c;
388 if ((j == 0 || j == 3) && zero)
389 c = 0;
390 else if (j == 3)
391 c = 0x5f;
392 else
393 c = 0x5f5f;
394
395 for (k = 0; k < 2; k++) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100396 mchbar_write32(0x138 + 8 * k, channel << 26 | j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100397 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Angel Ponsdea722b2021-03-26 14:11:12 +0100398 mchbar_read32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100399 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Angel Ponsdea722b2021-03-26 14:11:12 +0100400 mchbar_read32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100401 }
402
Angel Ponsdea722b2021-03-26 14:11:12 +0100403 mchbar_write32(0x334 + (channel << 10) + j * 0x44, zero ? 0 : val3[j]);
404 mchbar_write32(0x32c + (channel << 10) + j * 0x44,
405 zero ? 0 : 0x18191819 & lmask);
406 mchbar_write16(0x34a + (channel << 10) + j * 0x44, c);
407 mchbar_write32(0x33c + (channel << 10) + j * 0x44,
408 zero ? 0 : a & lmask);
409 mchbar_write32(0x344 + (channel << 10) + j * 0x44,
410 zero ? 0 : a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100411 }
412 }
413
Angel Ponsdea722b2021-03-26 14:11:12 +0100414 mchbar_setbits32(0x130, 1 << 0);
415 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +0200416 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100417}
418
Angel Pons244f4552021-01-15 20:41:36 +0100419static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100420{
421 u32 v;
422 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100423 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100424}
425
426static int find_highest_bit_set(u16 val)
427{
428 int i;
429 for (i = 15; i >= 0; i--)
430 if (val & (1 << i))
431 return i;
432 return -1;
433}
434
435static int find_lowest_bit_set32(u32 val)
436{
437 int i;
438 for (i = 0; i < 32; i++)
439 if (val & (1 << i))
440 return i;
441 return -1;
442}
443
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100444enum {
445 DEVICE_TYPE = 2,
446 MODULE_TYPE = 3,
447 DENSITY = 4,
448 RANKS_AND_DQ = 7,
449 MEMORY_BUS_WIDTH = 8,
450 TIMEBASE_DIVIDEND = 10,
451 TIMEBASE_DIVISOR = 11,
452 CYCLETIME = 12,
453
454 CAS_LATENCIES_LSB = 14,
455 CAS_LATENCIES_MSB = 15,
456 CAS_LATENCY_TIME = 16,
457 THERMAL_AND_REFRESH = 31,
458 REFERENCE_RAW_CARD_USED = 62,
459 RANK1_ADDRESS_MAPPING = 63
460};
461
462static void calculate_timings(struct raminfo *info)
463{
Martin Roth468d02c2019-10-23 21:44:42 -0600464 unsigned int cycletime;
465 unsigned int cas_latency_time;
466 unsigned int supported_cas_latencies;
467 unsigned int channel, slot;
468 unsigned int clock_speed_index;
469 unsigned int min_cas_latency;
470 unsigned int cas_latency;
471 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100472
473 /* Find common CAS latency */
474 supported_cas_latencies = 0x3fe;
475 for (channel = 0; channel < NUM_CHANNELS; channel++)
476 for (slot = 0; slot < NUM_SLOTS; slot++)
477 if (info->populated_ranks[channel][slot][0])
478 supported_cas_latencies &=
479 2 *
480 (info->
481 spd[channel][slot][CAS_LATENCIES_LSB] |
482 (info->
483 spd[channel][slot][CAS_LATENCIES_MSB] <<
484 8));
485
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100486 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100487
488 cycletime = min_cycletime[max_clock_index];
489 cas_latency_time = min_cas_latency_time[max_clock_index];
490
491 for (channel = 0; channel < NUM_CHANNELS; channel++)
492 for (slot = 0; slot < NUM_SLOTS; slot++)
493 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600494 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100495 timebase =
496 1000 *
497 info->
498 spd[channel][slot][TIMEBASE_DIVIDEND] /
499 info->spd[channel][slot][TIMEBASE_DIVISOR];
500 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100501 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100502 timebase *
503 info->spd[channel][slot][CYCLETIME]);
504 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100505 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100506 timebase *
507 info->
508 spd[channel][slot][CAS_LATENCY_TIME]);
509 }
Jacob Garber3c193822019-06-10 18:23:32 -0600510 if (cycletime > min_cycletime[0])
511 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100512 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
513 if (cycletime == min_cycletime[clock_speed_index])
514 break;
515 if (cycletime > min_cycletime[clock_speed_index]) {
516 clock_speed_index--;
517 cycletime = min_cycletime[clock_speed_index];
518 break;
519 }
520 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100521 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100522 cas_latency = 0;
523 while (supported_cas_latencies) {
524 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
525 if (cas_latency <= min_cas_latency)
526 break;
527 supported_cas_latencies &=
528 ~(1 << find_highest_bit_set(supported_cas_latencies));
529 }
530
531 if (cas_latency != min_cas_latency && clock_speed_index)
532 clock_speed_index--;
533
534 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
535 die("Couldn't configure DRAM");
536 info->clock_speed_index = clock_speed_index;
537 info->cas_latency = cas_latency;
538}
539
540static void program_base_timings(struct raminfo *info)
541{
Martin Roth468d02c2019-10-23 21:44:42 -0600542 unsigned int channel;
543 unsigned int slot, rank, lane;
544 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100545 int i;
546
547 extended_silicon_revision = info->silicon_revision;
548 if (info->silicon_revision == 0)
549 for (channel = 0; channel < NUM_CHANNELS; channel++)
550 for (slot = 0; slot < NUM_SLOTS; slot++)
551 if ((info->
552 spd[channel][slot][MODULE_TYPE] & 0xF) ==
553 3)
554 extended_silicon_revision = 4;
555
556 for (channel = 0; channel < NUM_CHANNELS; channel++) {
557 for (slot = 0; slot < NUM_SLOTS; slot++)
558 for (rank = 0; rank < NUM_SLOTS; rank++) {
559 int card_timing_2;
560 if (!info->populated_ranks[channel][slot][rank])
561 continue;
562
563 for (lane = 0; lane < 9; lane++) {
564 int tm_reg;
565 int card_timing;
566
567 card_timing = 0;
568 if ((info->
569 spd[channel][slot][MODULE_TYPE] &
570 0xF) == 3) {
571 int reference_card;
572 reference_card =
573 info->
574 spd[channel][slot]
575 [REFERENCE_RAW_CARD_USED] &
576 0x1f;
577 if (reference_card == 3)
578 card_timing =
579 u16_ffd1188[0][lane]
580 [info->
581 clock_speed_index];
582 if (reference_card == 5)
583 card_timing =
584 u16_ffd1188[1][lane]
585 [info->
586 clock_speed_index];
587 }
588
589 info->training.
590 lane_timings[0][channel][slot][rank]
591 [lane] =
592 u8_FFFD1218[info->
593 clock_speed_index];
594 info->training.
595 lane_timings[1][channel][slot][rank]
596 [lane] = 256;
597
598 for (tm_reg = 2; tm_reg < 4; tm_reg++)
599 info->training.
600 lane_timings[tm_reg]
601 [channel][slot][rank][lane]
602 =
603 u8_FFFD1240[channel]
604 [extended_silicon_revision]
605 [lane][2 * slot +
606 rank][info->
607 clock_speed_index]
608 + info->max4048[channel]
609 +
610 u8_FFFD0C78[channel]
611 [extended_silicon_revision]
612 [info->
613 mode4030[channel]][slot]
614 [rank][info->
615 clock_speed_index]
616 + card_timing;
617 for (tm_reg = 0; tm_reg < 4; tm_reg++)
618 write_500(info, channel,
619 info->training.
620 lane_timings[tm_reg]
621 [channel][slot][rank]
622 [lane],
623 get_timing_register_addr
624 (lane, tm_reg, slot,
625 rank), 9, 0);
626 }
627
628 card_timing_2 = 0;
629 if (!(extended_silicon_revision != 4
630 || (info->
631 populated_ranks_mask[channel] & 5) ==
632 5)) {
633 if ((info->
634 spd[channel][slot]
635 [REFERENCE_RAW_CARD_USED] & 0x1F)
636 == 3)
637 card_timing_2 =
638 u16_FFFE0EB8[0][info->
639 clock_speed_index];
640 if ((info->
641 spd[channel][slot]
642 [REFERENCE_RAW_CARD_USED] & 0x1F)
643 == 5)
644 card_timing_2 =
645 u16_FFFE0EB8[1][info->
646 clock_speed_index];
647 }
648
649 for (i = 0; i < 3; i++)
650 write_500(info, channel,
651 (card_timing_2 +
652 info->max4048[channel]
653 +
654 u8_FFFD0EF8[channel]
655 [extended_silicon_revision]
656 [info->
657 mode4030[channel]][info->
658 clock_speed_index]),
659 u16_fffd0c50[i][slot][rank],
660 8, 1);
661 write_500(info, channel,
662 (info->max4048[channel] +
663 u8_FFFD0C78[channel]
664 [extended_silicon_revision][info->
665 mode4030
666 [channel]]
667 [slot][rank][info->
668 clock_speed_index]),
669 u16_fffd0c70[slot][rank], 7, 1);
670 }
671 if (!info->populated_ranks_mask[channel])
672 continue;
673 for (i = 0; i < 3; i++)
674 write_500(info, channel,
675 (info->max4048[channel] +
676 info->avg4044[channel]
677 +
678 u8_FFFD17E0[channel]
679 [extended_silicon_revision][info->
680 mode4030
681 [channel]][info->
682 clock_speed_index]),
683 u16_fffd0c68[i], 8, 1);
684 }
685}
686
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100687/* The time of clock cycle in ps. */
688static unsigned int cycle_ps(struct raminfo *info)
689{
690 return 2 * halfcycle_ps(info);
691}
692
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100693/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600694static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100695{
696 return 100 * frequency_11(info) / 9;
697}
698
Martin Roth468d02c2019-10-23 21:44:42 -0600699static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100700{
701 return (frequency_11(info) * 2) * ps / 900000;
702}
703
Martin Roth468d02c2019-10-23 21:44:42 -0600704static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100705{
706 return (frequency_11(info)) * ns / 900;
707}
708
709static void compute_derived_timings(struct raminfo *info)
710{
Martin Roth468d02c2019-10-23 21:44:42 -0600711 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100712 int extended_silicon_revision;
713 int some_delay_1_ps;
714 int some_delay_2_ps;
715 int some_delay_2_halfcycles_ceil;
716 int some_delay_2_halfcycles_floor;
717 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100718 int some_delay_3_ps_rounded;
719 int some_delay_1_cycle_ceil;
720 int some_delay_1_cycle_floor;
721
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100722 some_delay_3_ps_rounded = 0;
723 extended_silicon_revision = info->silicon_revision;
724 if (!info->silicon_revision)
725 for (channel = 0; channel < NUM_CHANNELS; channel++)
726 for (slot = 0; slot < NUM_SLOTS; slot++)
727 if ((info->
728 spd[channel][slot][MODULE_TYPE] & 0xF) ==
729 3)
730 extended_silicon_revision = 4;
731 if (info->board_lane_delay[7] < 5)
732 info->board_lane_delay[7] = 5;
733 info->revision_flag_1 = 2;
734 if (info->silicon_revision == 2 || info->silicon_revision == 3)
735 info->revision_flag_1 = 0;
736 if (info->revision < 16)
737 info->revision_flag_1 = 0;
738
739 if (info->revision < 8)
740 info->revision_flag_1 = 0;
741 if (info->revision >= 8 && (info->silicon_revision == 0
742 || info->silicon_revision == 1))
743 some_delay_2_ps = 735;
744 else
745 some_delay_2_ps = 750;
746
747 if (info->revision >= 0x10 && (info->silicon_revision == 0
748 || info->silicon_revision == 1))
749 some_delay_1_ps = 3929;
750 else
751 some_delay_1_ps = 3490;
752
753 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
754 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
755 if (some_delay_1_ps % cycle_ps(info))
756 some_delay_1_cycle_ceil++;
757 else
758 some_delay_1_cycle_floor--;
759 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
760 if (info->revision_flag_1)
761 some_delay_2_ps = halfcycle_ps(info) >> 6;
762 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100763 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100764 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
765 375;
766 some_delay_3_ps =
767 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
768 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200769 if (some_delay_3_ps >= 150) {
770 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100771 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200772 some_delay_3_ps_rounded =
773 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
774 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100775 }
776 some_delay_2_halfcycles_ceil =
777 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
778 2 * (some_delay_1_cycle_ceil - 1);
779 if (info->revision_flag_1 && some_delay_3_ps < 150)
780 some_delay_2_halfcycles_ceil++;
781 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
782 if (info->revision < 0x10)
783 some_delay_2_halfcycles_floor =
784 some_delay_2_halfcycles_ceil - 1;
785 if (!info->revision_flag_1)
786 some_delay_2_halfcycles_floor++;
787 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
788 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
789 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
790 || (info->populated_ranks[1][0][0]
791 && info->populated_ranks[1][1][0]))
792 info->max_slots_used_in_channel = 2;
793 else
794 info->max_slots_used_in_channel = 1;
795 for (channel = 0; channel < 2; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +0100796 mchbar_write32(0x244 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +0200797 ((info->revision < 8) ? 1 : 0x200) |
798 ((2 - info->max_slots_used_in_channel) << 17) |
799 (channel << 21) |
Angel Ponsdea722b2021-03-26 14:11:12 +0100800 (info->some_delay_1_cycle_floor << 18) | 0x9510);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100801 if (info->max_slots_used_in_channel == 1) {
802 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
803 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
804 } else {
805 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
806 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
807 || (count_ranks_in_channel(info, 1) ==
808 2)) ? 2 : 3;
809 }
810 for (channel = 0; channel < NUM_CHANNELS; channel++) {
811 int max_of_unk;
812 int min_of_unk_2;
813
814 int i, count;
815 int sum;
816
817 if (!info->populated_ranks_mask[channel])
818 continue;
819
820 max_of_unk = 0;
821 min_of_unk_2 = 32767;
822
823 sum = 0;
824 count = 0;
825 for (i = 0; i < 3; i++) {
826 int unk1;
827 if (info->revision < 8)
828 unk1 =
829 u8_FFFD1891[0][channel][info->
830 clock_speed_index]
831 [i];
832 else if (!
833 (info->revision >= 0x10
834 || info->revision_flag_1))
835 unk1 =
836 u8_FFFD1891[1][channel][info->
837 clock_speed_index]
838 [i];
839 else
840 unk1 = 0;
841 for (slot = 0; slot < NUM_SLOTS; slot++)
842 for (rank = 0; rank < NUM_RANKS; rank++) {
843 int a = 0;
844 int b = 0;
845
846 if (!info->
847 populated_ranks[channel][slot]
848 [rank])
849 continue;
850 if (extended_silicon_revision == 4
851 && (info->
852 populated_ranks_mask[channel] &
853 5) != 5) {
854 if ((info->
855 spd[channel][slot]
856 [REFERENCE_RAW_CARD_USED] &
857 0x1F) == 3) {
858 a = u16_ffd1178[0]
859 [info->
860 clock_speed_index];
861 b = u16_fe0eb8[0][info->
862 clock_speed_index];
863 } else
864 if ((info->
865 spd[channel][slot]
866 [REFERENCE_RAW_CARD_USED]
867 & 0x1F) == 5) {
868 a = u16_ffd1178[1]
869 [info->
870 clock_speed_index];
871 b = u16_fe0eb8[1][info->
872 clock_speed_index];
873 }
874 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100875 min_of_unk_2 = MIN(min_of_unk_2, a);
876 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100877 if (rank == 0) {
878 sum += a;
879 count++;
880 }
881 {
882 int t;
883 t = b +
884 u8_FFFD0EF8[channel]
885 [extended_silicon_revision]
886 [info->
887 mode4030[channel]][info->
888 clock_speed_index];
889 if (unk1 >= t)
890 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100891 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 unk1 - t);
893 }
894 }
895 {
896 int t =
897 u8_FFFD17E0[channel]
898 [extended_silicon_revision][info->
899 mode4030
900 [channel]]
901 [info->clock_speed_index] + min_of_unk_2;
902 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100903 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100904 }
905 }
906
Jacob Garber64fb4a32019-06-10 17:29:18 -0600907 if (count == 0)
908 die("No memory ranks found for channel %u\n", channel);
909
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100910 info->avg4044[channel] = sum / count;
911 info->max4048[channel] = max_of_unk;
912 }
913}
914
915static void jedec_read(struct raminfo *info,
916 int channel, int slot, int rank,
917 int total_rank, u8 addr3, unsigned int value)
918{
919 /* Handle mirrored mapping. */
920 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +0200921 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
922 ((addr3 >> 1) & 0x10);
Angel Ponsdea722b2021-03-26 14:11:12 +0100923
924 mchbar_clrsetbits8(0x271, 0x1f << 1, addr3);
925 mchbar_clrsetbits8(0x671, 0x1f << 1, addr3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100926
927 /* Handle mirrored mapping. */
928 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
929 value =
930 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
931 << 1);
932
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800933 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100934
Angel Ponsdea722b2021-03-26 14:11:12 +0100935 mchbar_clrsetbits8(0x271, 0x1f << 1, 1 << 1);
936 mchbar_clrsetbits8(0x671, 0x1f << 1, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100937
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800938 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100939}
940
941enum {
942 MR1_RZQ12 = 512,
943 MR1_RZQ2 = 64,
944 MR1_RZQ4 = 4,
945 MR1_ODS34OHM = 2
946};
947
948enum {
949 MR0_BT_INTERLEAVED = 8,
950 MR0_DLL_RESET_ON = 256
951};
952
953enum {
954 MR2_RTT_WR_DISABLED = 0,
955 MR2_RZQ2 = 1 << 10
956};
957
958static void jedec_init(struct raminfo *info)
959{
960 int write_recovery;
961 int channel, slot, rank;
962 int total_rank;
963 int dll_on;
964 int self_refresh_temperature;
965 int auto_self_refresh;
966
967 auto_self_refresh = 1;
968 self_refresh_temperature = 1;
969 if (info->board_lane_delay[3] <= 10) {
970 if (info->board_lane_delay[3] <= 8)
971 write_recovery = info->board_lane_delay[3] - 4;
972 else
973 write_recovery = 5;
974 } else {
975 write_recovery = 6;
976 }
977 FOR_POPULATED_RANKS {
978 auto_self_refresh &=
979 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
980 self_refresh_temperature &=
981 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
982 }
983 if (auto_self_refresh == 1)
984 self_refresh_temperature = 0;
985
986 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
987 || (info->populated_ranks[0][0][0]
988 && info->populated_ranks[0][1][0])
989 || (info->populated_ranks[1][0][0]
990 && info->populated_ranks[1][1][0]));
991
992 total_rank = 0;
993
994 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
995 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
996 int rzq_reg58e;
997
998 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
999 rzq_reg58e = 64;
1000 rtt = MR1_RZQ2;
1001 if (info->clock_speed_index != 0) {
1002 rzq_reg58e = 4;
1003 if (info->populated_ranks_mask[channel] == 3)
1004 rtt = MR1_RZQ4;
1005 }
1006 } else {
1007 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1008 rtt = MR1_RZQ12;
1009 rzq_reg58e = 64;
1010 rtt_wr = MR2_RZQ2;
1011 } else {
1012 rzq_reg58e = 4;
1013 rtt = MR1_RZQ4;
1014 }
1015 }
1016
Angel Ponsdea722b2021-03-26 14:11:12 +01001017 mchbar_write16(0x588 + (channel << 10), 0);
1018 mchbar_write16(0x58a + (channel << 10), 4);
1019 mchbar_write16(0x58c + (channel << 10), rtt | MR1_ODS34OHM);
1020 mchbar_write16(0x58e + (channel << 10), rzq_reg58e | 0x82);
1021 mchbar_write16(0x590 + (channel << 10), 0x1282);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001022
1023 for (slot = 0; slot < NUM_SLOTS; slot++)
1024 for (rank = 0; rank < NUM_RANKS; rank++)
1025 if (info->populated_ranks[channel][slot][rank]) {
1026 jedec_read(info, channel, slot, rank,
1027 total_rank, 0x28,
1028 rtt_wr | (info->
1029 clock_speed_index
1030 << 3)
1031 | (auto_self_refresh << 6) |
1032 (self_refresh_temperature <<
1033 7));
1034 jedec_read(info, channel, slot, rank,
1035 total_rank, 0x38, 0);
1036 jedec_read(info, channel, slot, rank,
1037 total_rank, 0x18,
1038 rtt | MR1_ODS34OHM);
1039 jedec_read(info, channel, slot, rank,
1040 total_rank, 6,
1041 (dll_on << 12) |
1042 (write_recovery << 9)
1043 | ((info->cas_latency - 4) <<
1044 4) | MR0_BT_INTERLEAVED |
1045 MR0_DLL_RESET_ON);
1046 total_rank++;
1047 }
1048 }
1049}
1050
1051static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1052{
Martin Roth468d02c2019-10-23 21:44:42 -06001053 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001054 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1055 unsigned int channel_0_non_interleaved;
1056
1057 FOR_ALL_RANKS {
1058 if (info->populated_ranks[channel][slot][rank]) {
1059 total_mb[channel] +=
1060 pre_jedec ? 256 : (256 << info->
1061 density[channel][slot] >> info->
1062 is_x16_module[channel][slot]);
Angel Ponsdea722b2021-03-26 14:11:12 +01001063 mchbar_write8(0x208 + rank + 2 * slot + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001064 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1065 (info->is_x16_module[channel][slot] |
1066 ((info->density[channel][slot] + 1) << 1))) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001067 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001068 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001069 mchbar_write16(0x200 + (channel << 10) + 4 * slot + 2 * rank,
1070 total_mb[channel] >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001071 }
1072
1073 info->total_memory_mb = total_mb[0] + total_mb[1];
1074
1075 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001076 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001077 info->non_interleaved_part_mb =
1078 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1079 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001080 mchbar_write32(0x100, channel_0_non_interleaved | info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001081 if (!pre_jedec)
Angel Ponsdea722b2021-03-26 14:11:12 +01001082 mchbar_write16(0x104, info->interleaved_part_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001083}
1084
1085static void program_board_delay(struct raminfo *info)
1086{
1087 int cas_latency_shift;
1088 int some_delay_ns;
1089 int some_delay_3_half_cycles;
1090
Martin Roth468d02c2019-10-23 21:44:42 -06001091 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001092 int high_multiplier;
1093 int lane_3_delay;
1094 int cas_latency_derived;
1095
1096 high_multiplier = 0;
1097 some_delay_ns = 200;
1098 some_delay_3_half_cycles = 4;
1099 cas_latency_shift = info->silicon_revision == 0
1100 || info->silicon_revision == 1 ? 1 : 0;
1101 if (info->revision < 8) {
1102 some_delay_ns = 600;
1103 cas_latency_shift = 0;
1104 }
1105 {
1106 int speed_bit;
1107 speed_bit =
1108 ((info->clock_speed_index > 1
1109 || (info->silicon_revision != 2
1110 && info->silicon_revision != 3))) ^ (info->revision >=
1111 0x10);
1112 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1113 3, 1);
1114 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1115 3, 1);
1116 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1117 && (info->silicon_revision == 2
1118 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001119 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001120 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001121 mchbar_write32(0x120, 1 << (info->max_slots_used_in_channel + 28) | 0x188e7f9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001122
Angel Ponsdea722b2021-03-26 14:11:12 +01001123 mchbar_write8(0x124, info->board_lane_delay[4] + (frequency_01(info) + 999) / 1000);
1124 mchbar_write16(0x125, 0x1360);
1125 mchbar_write8(0x127, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001126 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001127 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001128 high_multiplier = 1;
1129 some_delay_2_half_cycles = ps_to_halfcycles(info,
1130 ((3 *
1131 fsbcycle_ps(info))
1132 >> 1) +
1133 (halfcycle_ps(info)
1134 *
1135 reg178_min[info->
1136 clock_speed_index]
1137 >> 6)
1138 +
1139 4 *
1140 halfcycle_ps(info)
1141 + 2230);
1142 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001143 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001144 (frequency_11(info) * 2) * (28 -
1145 some_delay_2_half_cycles) /
1146 (frequency_11(info) * 2 -
1147 4 * (info->fsb_frequency))) >> 3, 7);
1148 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001149 if (mchbar_read8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001150 some_delay_3_half_cycles = 3;
1151 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001152 mchbar_setbits32(0x220 + (channel << 10), 0x18001117);
1153 mchbar_write32(0x224 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001154 (info->max_slots_used_in_channel - 1) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001155 (info->cas_latency - 5 - info->clock_speed_index)
1156 << 21 | (info->max_slots_used_in_channel +
1157 info->cas_latency - cas_latency_shift - 4) << 16 |
1158 (info->cas_latency - cas_latency_shift - 4) << 26 |
1159 (info->cas_latency - info->clock_speed_index +
Felix Held04be2dd2018-07-29 04:53:22 +02001160 info->max_slots_used_in_channel - 6) << 8);
Angel Ponsdea722b2021-03-26 14:11:12 +01001161 mchbar_write32(0x228 + (channel << 10), info->max_slots_used_in_channel);
1162 mchbar_write8(0x239 + (channel << 10), 32);
1163 mchbar_write32(0x248 + (channel << 10), high_multiplier << 24 |
1164 some_delay_3_half_cycles << 25 | 0x840000);
1165 mchbar_write32(0x278 + (channel << 10), 0xc362042);
1166 mchbar_write32(0x27c + (channel << 10), 0x8b000062);
1167 mchbar_write32(0x24c + (channel << 10),
1168 (!!info->clock_speed_index) << 17 |
1169 ((2 + info->clock_speed_index -
1170 (!!info->clock_speed_index))) << 12 | 0x10200);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001171
Angel Ponsdea722b2021-03-26 14:11:12 +01001172 mchbar_write8(0x267 + (channel << 10), 4);
1173 mchbar_write16(0x272 + (channel << 10), 0x155);
1174 mchbar_clrsetbits32(0x2bc + (channel << 10), 0xffffff, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001175
1176 write_500(info, channel,
1177 ((!info->populated_ranks[channel][1][1])
1178 | (!info->populated_ranks[channel][1][0] << 1)
1179 | (!info->populated_ranks[channel][0][1] << 2)
1180 | (!info->populated_ranks[channel][0][0] << 3)),
1181 0x4c9, 4, 1);
1182 }
1183
Angel Ponsdea722b2021-03-26 14:11:12 +01001184 mchbar_write8(0x2c4, (1 + (info->clock_speed_index != 0)) << 6 | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001185 {
1186 u8 freq_divisor = 2;
1187 if (info->fsb_frequency == frequency_11(info))
1188 freq_divisor = 3;
1189 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1190 freq_divisor = 1;
1191 else
1192 freq_divisor = 2;
Angel Ponsdea722b2021-03-26 14:11:12 +01001193 mchbar_write32(0x2c0, freq_divisor << 11 | 0x6009c400);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001194 }
1195
1196 if (info->board_lane_delay[3] <= 10) {
1197 if (info->board_lane_delay[3] <= 8)
1198 lane_3_delay = info->board_lane_delay[3];
1199 else
1200 lane_3_delay = 10;
1201 } else {
1202 lane_3_delay = 12;
1203 }
1204 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1205 if (info->clock_speed_index > 1)
1206 cas_latency_derived++;
1207 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001208 mchbar_write32(0x240 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02001209 ((info->clock_speed_index == 0) * 0x11000) |
Angel Ponsdea722b2021-03-26 14:11:12 +01001210 0x1002100 | (2 + info->clock_speed_index) << 4 |
1211 (info->cas_latency - 3));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1213 0x609, 6, 1);
1214 write_500(info, channel,
1215 info->clock_speed_index + 2 * info->cas_latency - 7,
1216 0x601, 6, 1);
1217
Angel Ponsdea722b2021-03-26 14:11:12 +01001218 mchbar_write32(0x250 + (channel << 10),
1219 (lane_3_delay + info->clock_speed_index + 9) << 6 |
1220 info->board_lane_delay[7] << 2 |
1221 info->board_lane_delay[4] << 16 |
1222 info->board_lane_delay[1] << 25 |
1223 info->board_lane_delay[1] << 29 | 1);
1224 mchbar_write32(0x254 + (channel << 10),
1225 info->board_lane_delay[1] >> 3 |
1226 (info->board_lane_delay[8] + 4 * info->use_ecc) << 6 |
1227 0x80 | info->board_lane_delay[6] << 1 |
1228 info->board_lane_delay[2] << 28 |
1229 cas_latency_derived << 16 | 0x4700000);
1230 mchbar_write32(0x258 + (channel << 10),
1231 (info->board_lane_delay[5] + info->clock_speed_index + 9) << 12 |
1232 (info->clock_speed_index - info->cas_latency + 12) << 8 |
1233 info->board_lane_delay[2] << 17 |
1234 info->board_lane_delay[4] << 24 | 0x47);
1235 mchbar_write32(0x25c + (channel << 10),
1236 info->board_lane_delay[1] << 1 |
1237 info->board_lane_delay[0] << 8 | 0x1da50000);
1238 mchbar_write8(0x264 + (channel << 10), 0xff);
1239 mchbar_write8(0x5f8 + (channel << 10), cas_latency_shift << 3 | info->use_ecc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001240 }
1241
1242 program_modules_memory_map(info, 1);
1243
Angel Ponsdea722b2021-03-26 14:11:12 +01001244 mchbar_clrsetbits16(0x610, 0xfe3c,
1245 MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9 | 0x3c);
1246 mchbar_setbits16(0x612, 1 << 8);
1247 mchbar_setbits16(0x214, 0x3e00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001248 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001249 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001250 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001251 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001252 }
1253}
1254
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001255#define DEFAULT_PCI_MMIO_SIZE 2048
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001256
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001257static void program_total_memory_map(struct raminfo *info)
1258{
Angel Pons9333b742020-07-22 16:04:15 +02001259 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001261 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001262 unsigned int uma_base_igd;
1263 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001264 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001265 int memory_remap;
1266 unsigned int memory_map[8];
1267 int i;
1268 unsigned int current_limit;
1269 unsigned int tseg_base;
1270 int uma_size_igd = 0, uma_size_gtt = 0;
1271
1272 memset(memory_map, 0, sizeof(memory_map));
1273
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001275 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001276 gav(t);
1277 const int uma_sizes_gtt[16] =
1278 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1279 /* Igd memory */
1280 const int uma_sizes_igd[16] = {
1281 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1282 256, 512
1283 };
1284
1285 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1286 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1287 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001288
Angel Ponse24f97c2021-04-02 22:42:53 +02001289 mmio_size = DEFAULT_PCI_MMIO_SIZE;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001290
Angel Pons9333b742020-07-22 16:04:15 +02001291 tom = info->total_memory_mb;
1292 if (tom == 4096)
1293 tom = 4032;
1294 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1295 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1296 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001298 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001299 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001300 remap_base = MAX(4096, touud);
1301 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001302 }
Angel Pons9333b742020-07-22 16:04:15 +02001303 if (touud > 4096)
1304 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001305 quickpath_reserved = 0;
1306
Angel Pons3ab19b32020-07-22 16:29:54 +02001307 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001308
Jacob Garber975a7e32019-06-10 16:32:47 -06001309 gav(t);
1310
1311 if (t & 0x800) {
1312 u32 shift = t >> 20;
1313 if (shift == 0)
1314 die("Quickpath value is 0\n");
1315 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001316 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001317
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001318 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001319 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001320
Angel Pons9333b742020-07-22 16:04:15 +02001321 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001322 uma_base_gtt = uma_base_igd - uma_size_gtt;
1323 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1324 if (!memory_remap)
1325 tseg_base -= quickpath_reserved;
1326 tseg_base = ALIGN_DOWN(tseg_base, 8);
1327
Angel Pons16fe1e02020-07-22 16:12:33 +02001328 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1329 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001330 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001331 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1332 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001333 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001334 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001335
1336 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001337 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1338 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001339 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001340 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001341
1342 current_limit = 0;
1343 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1344 memory_map[1] = 4096;
1345 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001346 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001347 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001348 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1349 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001350 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351 }
1352}
1353
1354static void collect_system_info(struct raminfo *info)
1355{
1356 u32 capid0[3];
1357 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001358 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359
Angel Ponsb600d412021-01-16 16:33:48 +01001360 for (i = 0; i < 3; i++) {
1361 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1362 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1363 }
1364 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1365 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1366 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1367
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001368 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1369
1370 if ((capid0[1] >> 11) & 1)
1371 info->uma_enabled = 0;
1372 else
1373 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001374 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001375 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1376 info->silicon_revision = 0;
1377
1378 if (capid0[2] & 2) {
1379 info->silicon_revision = 0;
1380 info->max_supported_clock_speed_index = 2;
1381 for (channel = 0; channel < NUM_CHANNELS; channel++)
1382 if (info->populated_ranks[channel][0][0]
1383 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1384 3) {
1385 info->silicon_revision = 2;
1386 info->max_supported_clock_speed_index = 1;
1387 }
1388 } else {
1389 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1390 case 1:
1391 case 2:
1392 info->silicon_revision = 3;
1393 break;
1394 case 3:
1395 info->silicon_revision = 0;
1396 break;
1397 case 0:
1398 info->silicon_revision = 2;
1399 break;
1400 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001401 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001402 case 0x40:
1403 info->silicon_revision = 0;
1404 break;
1405 case 0x48:
1406 info->silicon_revision = 1;
1407 break;
1408 }
1409 }
1410}
1411
1412static void write_training_data(struct raminfo *info)
1413{
1414 int tm, channel, slot, rank, lane;
1415 if (info->revision < 8)
1416 return;
1417
1418 for (tm = 0; tm < 4; tm++)
1419 for (channel = 0; channel < NUM_CHANNELS; channel++)
1420 for (slot = 0; slot < NUM_SLOTS; slot++)
1421 for (rank = 0; rank < NUM_RANKS; rank++)
1422 for (lane = 0; lane < 9; lane++)
1423 write_500(info, channel,
1424 info->
1425 cached_training->
1426 lane_timings[tm]
1427 [channel][slot][rank]
1428 [lane],
1429 get_timing_register_addr
1430 (lane, tm, slot,
1431 rank), 9, 0);
1432 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1433 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1434}
1435
1436static void dump_timings(struct raminfo *info)
1437{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001439 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001441 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442 slot, rank);
1443 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001444 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001446 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447 read_500(info, channel,
1448 get_timing_register_addr
1449 (lane, i, slot, rank),
1450 9),
1451 info->training.
1452 lane_timings[i][channel][slot][rank]
1453 [lane]);
1454 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001455 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456 }
1457 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001458 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001460 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462}
1463
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001464/* Read timings and other registers that need to be restored verbatim and
1465 put them to CBMEM.
1466 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467static void save_timings(struct raminfo *info)
1468{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 int channel, slot, rank, lane, i;
1471
1472 train = info->training;
1473 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1474 for (i = 0; i < 4; i++)
1475 train.lane_timings[i][channel][slot][rank][lane] =
1476 read_500(info, channel,
1477 get_timing_register_addr(lane, i, slot,
1478 rank), 9);
1479 train.reg_178 = read_1d0(0x178, 7);
1480 train.reg_10b = read_1d0(0x10b, 6);
1481
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001482 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1483 u32 reg32;
Angel Ponsdea722b2021-03-26 14:11:12 +01001484 reg32 = mchbar_read32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001485 train.reg274265[channel][0] = reg32 >> 16;
1486 train.reg274265[channel][1] = reg32 & 0xffff;
Angel Ponsdea722b2021-03-26 14:11:12 +01001487 train.reg274265[channel][2] = mchbar_read16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001488 }
Angel Ponsdea722b2021-03-26 14:11:12 +01001489 train.reg2ca9_bit0 = mchbar_read8(0x2ca9) & 1;
1490 train.reg_6dc = mchbar_read32(0x6dc);
1491 train.reg_6e8 = mchbar_read32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001492
Arthur Heymansb3282092019-04-14 17:53:28 +02001493 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1494 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001495
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001496 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001497 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1498 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499}
1500
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001501static const struct ram_training *get_cached_training(void)
1502{
Shelley Chenad9cd682020-07-23 16:10:52 -07001503 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1504 MRC_CACHE_VERSION,
1505 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507
1508/* FIXME: add timeout. */
1509static void wait_heci_ready(void)
1510{
Felix Held04be2dd2018-07-29 04:53:22 +02001511 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1512 ;
Angel Ponseb537932020-09-14 19:18:11 +02001513
1514 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001515}
1516
1517/* FIXME: add timeout. */
1518static void wait_heci_cb_avail(int len)
1519{
1520 union {
1521 struct mei_csr csr;
1522 u32 raw;
1523 } csr;
1524
Felix Held22ca8cb2018-07-29 05:09:44 +02001525 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1526 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001527
Angel Ponseb537932020-09-14 19:18:11 +02001528 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001529 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001530 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1531 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001532}
1533
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001534static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001535{
1536 int len = (head->length + 3) / 4;
1537 int i;
1538
1539 wait_heci_cb_avail(len + 1);
1540
1541 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001542 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001543 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001544 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001545
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001546 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1547 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001548}
1549
Angel Ponseb537932020-09-14 19:18:11 +02001550static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001551{
1552 struct mei_header head;
1553 int maxlen;
1554
1555 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001556 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001557
1558 while (len) {
1559 int cur = len;
1560 if (cur > maxlen) {
1561 cur = maxlen;
1562 head.is_complete = 0;
1563 } else
1564 head.is_complete = 1;
1565 head.length = cur;
1566 head.reserved = 0;
1567 head.client_address = clientaddress;
1568 head.host_address = hostaddress;
1569 send_heci_packet(&head, (u32 *) msg);
1570 len -= cur;
1571 msg += cur;
1572 }
1573}
1574
1575/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001576static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577{
1578 union {
1579 struct mei_csr csr;
1580 u32 raw;
1581 } csr;
1582 int i = 0;
1583
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001584 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001586 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001587 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1588
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001589 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001590 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001591 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592 *packet_size = 0;
1593 return 0;
1594 }
Angel Ponseb537932020-09-14 19:18:11 +02001595 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001596 *packet_size = 0;
1597 return -1;
1598 }
1599
Angel Ponseb537932020-09-14 19:18:11 +02001600 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001601 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001602 } while (((head->length + 3) >> 2) >
1603 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001604
1605 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001606 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607 *packet_size = head->length;
1608 if (!csr.csr.ready)
1609 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001610 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001611 return 0;
1612}
1613
Angel Ponsb1821892020-09-14 19:29:53 +02001614union uma_reply {
1615 struct {
1616 u8 group_id;
1617 u8 command;
1618 u8 reserved;
1619 u8 result;
1620 u8 field2;
1621 u8 unk3[0x48 - 4 - 1];
1622 };
1623 u32 dwords[0x48 / sizeof(u32)];
1624} __packed;
1625
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626/* FIXME: Add timeout. */
Angel Ponsb1821892020-09-14 19:29:53 +02001627static int recv_heci_message(union uma_reply *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628{
1629 struct mei_header head;
1630 int current_position;
1631
1632 current_position = 0;
1633 while (1) {
1634 u32 current_size;
1635 current_size = *message_size - current_position;
1636 if (recv_heci_packet
Angel Ponsb1821892020-09-14 19:29:53 +02001637 (&head, &message->dwords[current_position / sizeof(u32)],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638 &current_size) == -1)
1639 break;
1640 if (!current_size)
1641 break;
1642 current_position += current_size;
1643 if (head.is_complete) {
1644 *message_size = current_position;
1645 return 0;
1646 }
1647
1648 if (current_position >= *message_size)
1649 break;
1650 }
1651 *message_size = 0;
1652 return -1;
1653}
1654
Angel Pons55f11e22020-09-14 19:06:53 +02001655static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656{
Angel Ponsb1821892020-09-14 19:29:53 +02001657 union uma_reply reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001658
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659 struct uma_message {
1660 u8 group_id;
1661 u8 cmd;
1662 u8 reserved;
1663 u8 result;
1664 u32 c2;
1665 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001666 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001668 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001669 .group_id = 0,
1670 .cmd = MKHI_SET_UMA,
1671 .reserved = 0,
1672 .result = 0,
1673 .c2 = 0x82,
1674 .heci_uma_addr = heci_uma_addr,
1675 .heci_uma_size = heci_uma_size,
1676 .c3 = 0,
1677 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678 u32 reply_size;
1679
Angel Ponseb537932020-09-14 19:18:11 +02001680 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681
1682 reply_size = sizeof(reply);
Angel Ponsb1821892020-09-14 19:29:53 +02001683 if (recv_heci_message(&reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001684 return;
1685
1686 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1687 die("HECI init failed\n");
1688}
1689
1690static void setup_heci_uma(struct raminfo *info)
1691{
Angel Pons44479962021-02-24 23:08:27 +01001692 if (!info->memory_reserved_for_heci_mb || !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001693 return;
1694
Angel Pons36592bf2020-09-14 18:52:44 +02001695 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001697 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001698 info->memory_reserved_for_heci_mb)) << 20;
1699
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001700 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001701 if (info->memory_reserved_for_heci_mb) {
Angel Ponsdea722b2021-03-26 14:11:12 +01001702 dmibar_clrbits32(DMIVC0RCTL, 1 << 7);
Angel Ponsee7fb342021-01-28 14:11:55 +01001703 RCBA32(0x14) &= ~0x80;
Angel Ponsdea722b2021-03-26 14:11:12 +01001704 dmibar_clrbits32(DMIVC1RCTL, 1 << 7);
Angel Ponsee7fb342021-01-28 14:11:55 +01001705 RCBA32(0x20) &= ~0x80;
Angel Ponsdea722b2021-03-26 14:11:12 +01001706 dmibar_clrbits32(DMIVCPRCTL, 1 << 7);
Angel Ponsee7fb342021-01-28 14:11:55 +01001707 RCBA32(0x30) &= ~0x80;
Angel Ponsdea722b2021-03-26 14:11:12 +01001708 dmibar_clrbits32(DMIVCMRCTL, 1 << 7);
Angel Ponsee7fb342021-01-28 14:11:55 +01001709 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001710
Angel Ponsee7fb342021-01-28 14:11:55 +01001711 RCBA32(0x40) = 0x87000080; // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01001712 dmibar_write32(DMIVCMRCTL, 0x87000080); // OK
Angel Ponseb537932020-09-14 19:18:11 +02001713
Angel Ponsdea722b2021-03-26 14:11:12 +01001714 while ((RCBA16(0x46) & 2) && dmibar_read16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001715 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 }
1717
Angel Ponsdea722b2021-03-26 14:11:12 +01001718 mchbar_write32(0x24, 0x10000 + info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001719
Angel Pons55f11e22020-09-14 19:06:53 +02001720 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001721
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001722 pci_write_config32(HECIDEV, 0x10, 0x0);
1723 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724}
1725
1726static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1727{
1728 int ranks_in_channel;
1729 ranks_in_channel = info->populated_ranks[channel][0][0]
1730 + info->populated_ranks[channel][0][1]
1731 + info->populated_ranks[channel][1][0]
1732 + info->populated_ranks[channel][1][1];
1733
1734 /* empty channel */
1735 if (ranks_in_channel == 0)
1736 return 1;
1737
1738 if (ranks_in_channel != ranks)
1739 return 0;
1740 /* single slot */
1741 if (info->populated_ranks[channel][0][0] !=
1742 info->populated_ranks[channel][1][0])
1743 return 1;
1744 if (info->populated_ranks[channel][0][1] !=
1745 info->populated_ranks[channel][1][1])
1746 return 1;
1747 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1748 return 0;
1749 if (info->density[channel][0] != info->density[channel][1])
1750 return 0;
1751 return 1;
1752}
1753
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754static void read_4090(struct raminfo *info)
1755{
1756 int i, channel, slot, rank, lane;
1757 for (i = 0; i < 2; i++)
1758 for (slot = 0; slot < NUM_SLOTS; slot++)
1759 for (rank = 0; rank < NUM_RANKS; rank++)
1760 for (lane = 0; lane < 9; lane++)
1761 info->training.
1762 lane_timings[0][i][slot][rank][lane]
1763 = 32;
1764
1765 for (i = 1; i < 4; i++)
1766 for (channel = 0; channel < NUM_CHANNELS; channel++)
1767 for (slot = 0; slot < NUM_SLOTS; slot++)
1768 for (rank = 0; rank < NUM_RANKS; rank++)
1769 for (lane = 0; lane < 9; lane++) {
1770 info->training.
1771 lane_timings[i][channel]
1772 [slot][rank][lane] =
1773 read_500(info, channel,
1774 get_timing_register_addr
1775 (lane, i, slot,
1776 rank), 9)
1777 + (i == 1) * 11; // !!!!
1778 }
1779
1780}
1781
1782static u32 get_etalon2(int flip, u32 addr)
1783{
1784 const u16 invmask[] = {
1785 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1786 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1787 };
1788 u32 ret;
1789 u32 comp4 = addr / 480;
1790 addr %= 480;
1791 u32 comp1 = addr & 0xf;
1792 u32 comp2 = (addr >> 4) & 1;
1793 u32 comp3 = addr >> 5;
1794
1795 if (comp4)
1796 ret = 0x1010101 << (comp4 - 1);
1797 else
1798 ret = 0;
1799 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1800 ret = ~ret;
1801
1802 return ret;
1803}
1804
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001805static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806{
1807 msr_t msr = {.lo = 0, .hi = 0 };
1808
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001809 wrmsr(MTRR_PHYS_BASE(3), msr);
1810 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001811}
1812
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001813static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001814{
1815 msr_t msr;
1816 msr.lo = base | MTRR_TYPE_WRPROT;
1817 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001818 wrmsr(MTRR_PHYS_BASE(3), msr);
1819 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001820 & 0xffffffff);
1821 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001822 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001823}
1824
1825static void flush_cache(u32 start, u32 size)
1826{
1827 u32 end;
1828 u32 addr;
1829
1830 end = start + (ALIGN_DOWN(size + 4096, 4096));
1831 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001832 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833}
1834
1835static void clear_errors(void)
1836{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001837 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838}
1839
1840static void write_testing(struct raminfo *info, int totalrank, int flip)
1841{
1842 int nwrites = 0;
1843 /* in 8-byte units. */
1844 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001845 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846
Patrick Rudolph819c2062019-11-29 19:27:37 +01001847 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001848 for (offset = 0; offset < 9 * 480; offset += 2) {
1849 write32(base + offset * 8, get_etalon2(flip, offset));
1850 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1851 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1852 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1853 nwrites += 4;
1854 if (nwrites >= 320) {
1855 clear_errors();
1856 nwrites = 0;
1857 }
1858 }
1859}
1860
1861static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1862{
1863 u8 failmask = 0;
1864 int i;
1865 int comp1, comp2, comp3;
1866 u32 failxor[2] = { 0, 0 };
1867
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001868 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869
1870 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1871 for (comp1 = 0; comp1 < 4; comp1++)
1872 for (comp2 = 0; comp2 < 60; comp2++) {
1873 u32 re[4];
1874 u32 curroffset =
1875 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1876 read128((total_rank << 28) | (curroffset << 3),
1877 (u64 *) re);
1878 failxor[0] |=
1879 get_etalon2(flip, curroffset) ^ re[0];
1880 failxor[1] |=
1881 get_etalon2(flip, curroffset) ^ re[1];
1882 failxor[0] |=
1883 get_etalon2(flip, curroffset | 1) ^ re[2];
1884 failxor[1] |=
1885 get_etalon2(flip, curroffset | 1) ^ re[3];
1886 }
1887 for (i = 0; i < 8; i++)
1888 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1889 failmask |= 1 << i;
1890 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001891 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001892 flush_cache((total_rank << 28), 1728 * 5 * 4);
1893 return failmask;
1894}
1895
1896const u32 seed1[0x18] = {
1897 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1898 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1899 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1900 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1901 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1902 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1903};
1904
1905static u32 get_seed2(int a, int b)
1906{
1907 const u32 seed2[5] = {
1908 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1909 0x5b6db6db,
1910 };
1911 u32 r;
1912 r = seed2[(a + (a >= 10)) / 5];
1913 return b ? ~r : r;
1914}
1915
1916static int make_shift(int comp2, int comp5, int x)
1917{
1918 const u8 seed3[32] = {
1919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1920 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1921 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1922 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1923 };
1924
1925 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1926}
1927
1928static u32 get_etalon(int flip, u32 addr)
1929{
1930 u32 mask_byte = 0;
1931 int comp1 = (addr >> 1) & 1;
1932 int comp2 = (addr >> 3) & 0x1f;
1933 int comp3 = (addr >> 8) & 0xf;
1934 int comp4 = (addr >> 12) & 0xf;
1935 int comp5 = (addr >> 16) & 0x1f;
1936 u32 mask_bit = ~(0x10001 << comp3);
1937 u32 part1;
1938 u32 part2;
1939 int byte;
1940
1941 part2 =
1942 ((seed1[comp5] >>
1943 make_shift(comp2, comp5,
1944 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1945 part1 =
1946 ((seed1[comp5] >>
1947 make_shift(comp2, comp5,
1948 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1949
1950 for (byte = 0; byte < 4; byte++)
1951 if ((get_seed2(comp5, comp4) >>
1952 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1953 mask_byte |= 0xff << (8 * byte);
1954
1955 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1956 (comp3 + 16));
1957}
1958
1959static void
1960write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1961 char flip)
1962{
1963 int i;
1964 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001965 write32p((totalrank << 28) | (region << 25) | (block << 16) |
1966 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967}
1968
1969static u8
1970check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1971 char flip)
1972{
1973 u8 failmask = 0;
1974 u32 failxor[2];
1975 int i;
1976 int comp1, comp2, comp3;
1977
1978 failxor[0] = 0;
1979 failxor[1] = 0;
1980
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001981 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001982 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
1983 for (comp1 = 0; comp1 < 16; comp1++)
1984 for (comp2 = 0; comp2 < 64; comp2++) {
1985 u32 addr =
1986 (totalrank << 28) | (region << 25) | (block
1987 << 16)
1988 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
1989 2);
1990 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001991 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001992 }
1993 for (i = 0; i < 8; i++)
1994 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1995 failmask |= 1 << i;
1996 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001997 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001998 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
1999 return failmask;
2000}
2001
2002static int check_bounded(unsigned short *vals, u16 bound)
2003{
2004 int i;
2005
2006 for (i = 0; i < 8; i++)
2007 if (vals[i] < bound)
2008 return 0;
2009 return 1;
2010}
2011
2012enum state {
2013 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2014};
2015
2016static int validate_state(enum state *in)
2017{
2018 int i;
2019 for (i = 0; i < 8; i++)
2020 if (in[i] != COMPLETE)
2021 return 0;
2022 return 1;
2023}
2024
2025static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002026do_fsm(enum state *state, u16 *counter,
2027 u8 fail_mask, int margin, int uplimit,
2028 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002029{
2030 int lane;
2031
2032 for (lane = 0; lane < 8; lane++) {
2033 int is_fail = (fail_mask >> lane) & 1;
2034 switch (state[lane]) {
2035 case BEFORE_USABLE:
2036 if (!is_fail) {
2037 counter[lane] = 1;
2038 state[lane] = AT_USABLE;
2039 break;
2040 }
2041 counter[lane] = 0;
2042 state[lane] = BEFORE_USABLE;
2043 break;
2044 case AT_USABLE:
2045 if (!is_fail) {
2046 ++counter[lane];
2047 if (counter[lane] >= margin) {
2048 state[lane] = AT_MARGIN;
2049 res_low[lane] = val - margin + 1;
2050 break;
2051 }
2052 state[lane] = 1;
2053 break;
2054 }
2055 counter[lane] = 0;
2056 state[lane] = BEFORE_USABLE;
2057 break;
2058 case AT_MARGIN:
2059 if (is_fail) {
2060 state[lane] = COMPLETE;
2061 res_high[lane] = val - 1;
2062 } else {
2063 counter[lane]++;
2064 state[lane] = AT_MARGIN;
2065 if (val == uplimit) {
2066 state[lane] = COMPLETE;
2067 res_high[lane] = uplimit;
2068 }
2069 }
2070 break;
2071 case COMPLETE:
2072 break;
2073 }
2074 }
2075}
2076
2077static void
2078train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2079 u8 total_rank, u8 reg_178, int first_run, int niter,
2080 timing_bounds_t * timings)
2081{
2082 int lane;
2083 enum state state[8];
2084 u16 count[8];
2085 u8 lower_usable[8];
2086 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002087 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002088 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002089 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002090
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002091 for (i = 0; i < 8; i++)
2092 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002093
2094 if (!first_run) {
2095 int is_all_ok = 1;
2096 for (lane = 0; lane < 8; lane++)
2097 if (timings[reg_178][channel][slot][rank][lane].
2098 smallest ==
2099 timings[reg_178][channel][slot][rank][lane].
2100 largest) {
2101 timings[reg_178][channel][slot][rank][lane].
2102 smallest = 0;
2103 timings[reg_178][channel][slot][rank][lane].
2104 largest = 0;
2105 is_all_ok = 0;
2106 }
2107 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002108 for (i = 0; i < 8; i++)
2109 state[i] = COMPLETE;
2110 }
2111 }
2112
2113 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2114 u8 failmask = 0;
2115 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2116 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2117 failmask = check_testing(info, total_rank, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01002118 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002119 do_fsm(state, count, failmask, 5, 47, lower_usable,
2120 upper_usable, reg1b3);
2121 }
2122
2123 if (reg1b3) {
2124 write_1d0(0, 0x1b3, 6, 1);
2125 write_1d0(0, 0x1a3, 6, 1);
2126 for (lane = 0; lane < 8; lane++) {
2127 if (state[lane] == COMPLETE) {
2128 timings[reg_178][channel][slot][rank][lane].
2129 smallest =
2130 lower_usable[lane] +
2131 (info->training.
2132 lane_timings[0][channel][slot][rank][lane]
2133 & 0x3F) - 32;
2134 timings[reg_178][channel][slot][rank][lane].
2135 largest =
2136 upper_usable[lane] +
2137 (info->training.
2138 lane_timings[0][channel][slot][rank][lane]
2139 & 0x3F) - 32;
2140 }
2141 }
2142 }
2143
2144 if (!first_run) {
2145 for (lane = 0; lane < 8; lane++)
2146 if (state[lane] == COMPLETE) {
2147 write_500(info, channel,
2148 timings[reg_178][channel][slot][rank]
2149 [lane].smallest,
2150 get_timing_register_addr(lane, 0,
2151 slot, rank),
2152 9, 1);
2153 write_500(info, channel,
2154 timings[reg_178][channel][slot][rank]
2155 [lane].smallest +
2156 info->training.
2157 lane_timings[1][channel][slot][rank]
2158 [lane]
2159 -
2160 info->training.
2161 lane_timings[0][channel][slot][rank]
2162 [lane], get_timing_register_addr(lane,
2163 1,
2164 slot,
2165 rank),
2166 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002167 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002168 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002169 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002170
2171 do {
2172 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002173 for (i = 0; i < niter; i++) {
2174 if (failmask == 0xFF)
2175 break;
2176 failmask |=
2177 check_testing_type2(info, total_rank, 2, i,
2178 0);
2179 failmask |=
2180 check_testing_type2(info, total_rank, 3, i,
2181 1);
2182 }
Angel Ponsdea722b2021-03-26 14:11:12 +01002183 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002184 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002185 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002186 if ((1 << lane) & failmask) {
2187 if (timings[reg_178][channel]
2188 [slot][rank][lane].
2189 largest <=
2190 timings[reg_178][channel]
2191 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002192 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002193 [lane] = -1;
2194 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002195 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002196 [lane] = 0;
2197 timings[reg_178]
2198 [channel][slot]
2199 [rank][lane].
2200 smallest++;
2201 write_500(info, channel,
2202 timings
2203 [reg_178]
2204 [channel]
2205 [slot][rank]
2206 [lane].
2207 smallest,
2208 get_timing_register_addr
2209 (lane, 0,
2210 slot, rank),
2211 9, 1);
2212 write_500(info, channel,
2213 timings
2214 [reg_178]
2215 [channel]
2216 [slot][rank]
2217 [lane].
2218 smallest +
2219 info->
2220 training.
2221 lane_timings
2222 [1][channel]
2223 [slot][rank]
2224 [lane]
2225 -
2226 info->
2227 training.
2228 lane_timings
2229 [0][channel]
2230 [slot][rank]
2231 [lane],
2232 get_timing_register_addr
2233 (lane, 1,
2234 slot, rank),
2235 9, 1);
2236 }
2237 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002238 num_successfully_checked[lane]
2239 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002240 }
2241 }
Felix Held04be2dd2018-07-29 04:53:22 +02002242 while (!check_bounded(num_successfully_checked, 2))
2243 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002244
2245 for (lane = 0; lane < 8; lane++)
2246 if (state[lane] == COMPLETE) {
2247 write_500(info, channel,
2248 timings[reg_178][channel][slot][rank]
2249 [lane].largest,
2250 get_timing_register_addr(lane, 0,
2251 slot, rank),
2252 9, 1);
2253 write_500(info, channel,
2254 timings[reg_178][channel][slot][rank]
2255 [lane].largest +
2256 info->training.
2257 lane_timings[1][channel][slot][rank]
2258 [lane]
2259 -
2260 info->training.
2261 lane_timings[0][channel][slot][rank]
2262 [lane], get_timing_register_addr(lane,
2263 1,
2264 slot,
2265 rank),
2266 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002267 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002268 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002269 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002270
2271 do {
2272 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002273 for (i = 0; i < niter; i++) {
2274 if (failmask == 0xFF)
2275 break;
2276 failmask |=
2277 check_testing_type2(info, total_rank, 2, i,
2278 0);
2279 failmask |=
2280 check_testing_type2(info, total_rank, 3, i,
2281 1);
2282 }
2283
Angel Ponsdea722b2021-03-26 14:11:12 +01002284 mchbar_setbits32(0xfb0, 3 << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002285 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002286 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002287 if ((1 << lane) & failmask) {
2288 if (timings[reg_178][channel]
2289 [slot][rank][lane].
2290 largest <=
2291 timings[reg_178][channel]
2292 [slot][rank][lane].
2293 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002294 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002295 [lane] = -1;
2296 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002297 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002298 [lane] = 0;
2299 timings[reg_178]
2300 [channel][slot]
2301 [rank][lane].
2302 largest--;
2303 write_500(info, channel,
2304 timings
2305 [reg_178]
2306 [channel]
2307 [slot][rank]
2308 [lane].
2309 largest,
2310 get_timing_register_addr
2311 (lane, 0,
2312 slot, rank),
2313 9, 1);
2314 write_500(info, channel,
2315 timings
2316 [reg_178]
2317 [channel]
2318 [slot][rank]
2319 [lane].
2320 largest +
2321 info->
2322 training.
2323 lane_timings
2324 [1][channel]
2325 [slot][rank]
2326 [lane]
2327 -
2328 info->
2329 training.
2330 lane_timings
2331 [0][channel]
2332 [slot][rank]
2333 [lane],
2334 get_timing_register_addr
2335 (lane, 1,
2336 slot, rank),
2337 9, 1);
2338 }
2339 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002340 num_successfully_checked[lane]
2341 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002342 }
2343 }
2344 }
Felix Held04be2dd2018-07-29 04:53:22 +02002345 while (!check_bounded(num_successfully_checked, 3))
2346 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002347
2348 for (lane = 0; lane < 8; lane++) {
2349 write_500(info, channel,
2350 info->training.
2351 lane_timings[0][channel][slot][rank][lane],
2352 get_timing_register_addr(lane, 0, slot, rank),
2353 9, 1);
2354 write_500(info, channel,
2355 info->training.
2356 lane_timings[1][channel][slot][rank][lane],
2357 get_timing_register_addr(lane, 1, slot, rank),
2358 9, 1);
2359 if (timings[reg_178][channel][slot][rank][lane].
2360 largest <=
2361 timings[reg_178][channel][slot][rank][lane].
2362 smallest) {
2363 timings[reg_178][channel][slot][rank][lane].
2364 largest = 0;
2365 timings[reg_178][channel][slot][rank][lane].
2366 smallest = 0;
2367 }
2368 }
2369 }
2370}
2371
2372static void set_10b(struct raminfo *info, u8 val)
2373{
2374 int channel;
2375 int slot, rank;
2376 int lane;
2377
2378 if (read_1d0(0x10b, 6) == val)
2379 return;
2380
2381 write_1d0(val, 0x10b, 6, 1);
2382
2383 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2384 u16 reg_500;
2385 reg_500 = read_500(info, channel,
2386 get_timing_register_addr(lane, 0, slot,
2387 rank), 9);
2388 if (val == 1) {
2389 if (lut16[info->clock_speed_index] <= reg_500)
2390 reg_500 -= lut16[info->clock_speed_index];
2391 else
2392 reg_500 = 0;
2393 } else {
2394 reg_500 += lut16[info->clock_speed_index];
2395 }
2396 write_500(info, channel, reg_500,
2397 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2398 }
2399}
2400
2401static void set_ecc(int onoff)
2402{
2403 int channel;
2404 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2405 u8 t;
Angel Ponsdea722b2021-03-26 14:11:12 +01002406 t = mchbar_read8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002407 if (onoff)
2408 t |= 1;
2409 else
2410 t &= ~1;
Angel Ponsdea722b2021-03-26 14:11:12 +01002411 mchbar_write8((channel << 10) + 0x5f8, t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002412 }
2413}
2414
2415static void set_178(u8 val)
2416{
2417 if (val >= 31)
2418 val = val - 31;
2419 else
2420 val = 63 - val;
2421
2422 write_1d0(2 * val, 0x178, 7, 1);
2423}
2424
2425static void
2426write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2427 int type)
2428{
2429 int lane;
2430
2431 for (lane = 0; lane < 8; lane++)
2432 write_500(info, channel,
2433 info->training.
2434 lane_timings[type][channel][slot][rank][lane],
2435 get_timing_register_addr(lane, type, slot, rank), 9,
2436 0);
2437}
2438
2439static void
2440try_timing_offsets(struct raminfo *info, int channel,
2441 int slot, int rank, int totalrank)
2442{
2443 u16 count[8];
2444 enum state state[8];
2445 u8 lower_usable[8], upper_usable[8];
2446 int lane;
2447 int i;
2448 int flip = 1;
2449 int timing_offset;
2450
2451 for (i = 0; i < 8; i++)
2452 state[i] = BEFORE_USABLE;
2453
2454 memset(count, 0, sizeof(count));
2455
2456 for (lane = 0; lane < 8; lane++)
2457 write_500(info, channel,
2458 info->training.
2459 lane_timings[2][channel][slot][rank][lane] + 32,
2460 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2461
2462 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2463 timing_offset++) {
2464 u8 failmask;
2465 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2466 failmask = 0;
2467 for (i = 0; i < 2 && failmask != 0xff; i++) {
2468 flip = !flip;
2469 write_testing(info, totalrank, flip);
2470 failmask |= check_testing(info, totalrank, flip);
2471 }
2472 do_fsm(state, count, failmask, 10, 63, lower_usable,
2473 upper_usable, timing_offset);
2474 }
2475 write_1d0(0, 0x1bb, 6, 1);
2476 dump_timings(info);
2477 if (!validate_state(state))
2478 die("Couldn't discover DRAM timings (1)\n");
2479
2480 for (lane = 0; lane < 8; lane++) {
2481 u8 bias = 0;
2482
2483 if (info->silicon_revision) {
2484 int usable_length;
2485
2486 usable_length = upper_usable[lane] - lower_usable[lane];
2487 if (usable_length >= 20) {
2488 bias = usable_length / 2 - 10;
2489 if (bias >= 2)
2490 bias = 2;
2491 }
2492 }
2493 write_500(info, channel,
2494 info->training.
2495 lane_timings[2][channel][slot][rank][lane] +
2496 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2497 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2498 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2499 info->training.lane_timings[2][channel][slot][rank][lane] +
2500 lower_usable[lane];
2501 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2502 info->training.lane_timings[2][channel][slot][rank][lane] +
2503 upper_usable[lane];
2504 info->training.timing2_offset[channel][slot][rank][lane] =
2505 info->training.lane_timings[2][channel][slot][rank][lane];
2506 }
2507}
2508
2509static u8
2510choose_training(struct raminfo *info, int channel, int slot, int rank,
2511 int lane, timing_bounds_t * timings, u8 center_178)
2512{
2513 u16 central_weight;
2514 u16 side_weight;
2515 unsigned int sum = 0, count = 0;
2516 u8 span;
2517 u8 lower_margin, upper_margin;
2518 u8 reg_178;
2519 u8 result;
2520
2521 span = 12;
2522 central_weight = 20;
2523 side_weight = 20;
2524 if (info->silicon_revision == 1 && channel == 1) {
2525 central_weight = 5;
2526 side_weight = 20;
2527 if ((info->
2528 populated_ranks_mask[1] ^ (info->
2529 populated_ranks_mask[1] >> 2)) &
2530 1)
2531 span = 18;
2532 }
2533 if ((info->populated_ranks_mask[0] & 5) == 5) {
2534 central_weight = 20;
2535 side_weight = 20;
2536 }
2537 if (info->clock_speed_index >= 2
2538 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2539 if (info->silicon_revision == 1) {
2540 switch (channel) {
2541 case 0:
2542 if (lane == 1) {
2543 central_weight = 10;
2544 side_weight = 20;
2545 }
2546 break;
2547 case 1:
2548 if (lane == 6) {
2549 side_weight = 5;
2550 central_weight = 20;
2551 }
2552 break;
2553 }
2554 }
2555 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2556 side_weight = 5;
2557 central_weight = 20;
2558 }
2559 }
2560 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2561 reg_178 += span) {
2562 u8 smallest;
2563 u8 largest;
2564 largest = timings[reg_178][channel][slot][rank][lane].largest;
2565 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2566 if (largest - smallest + 1 >= 5) {
2567 unsigned int weight;
2568 if (reg_178 == center_178)
2569 weight = central_weight;
2570 else
2571 weight = side_weight;
2572 sum += weight * (largest + smallest);
2573 count += weight;
2574 }
2575 }
2576 dump_timings(info);
2577 if (count == 0)
2578 die("Couldn't discover DRAM timings (2)\n");
2579 result = sum / (2 * count);
2580 lower_margin =
2581 result - timings[center_178][channel][slot][rank][lane].smallest;
2582 upper_margin =
2583 timings[center_178][channel][slot][rank][lane].largest - result;
2584 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002585 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002586 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002587 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002588 return result;
2589}
2590
2591#define STANDARD_MIN_MARGIN 5
2592
2593static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2594{
2595 u16 margin[64];
2596 int lane, rank, slot, channel;
2597 u8 reg178;
2598 int count = 0, sum = 0;
2599
2600 for (reg178 = reg178_min[info->clock_speed_index];
2601 reg178 < reg178_max[info->clock_speed_index];
2602 reg178 += reg178_step[info->clock_speed_index]) {
2603 margin[reg178] = -1;
2604 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2605 int curmargin =
2606 timings[reg178][channel][slot][rank][lane].largest -
2607 timings[reg178][channel][slot][rank][lane].
2608 smallest + 1;
2609 if (curmargin < margin[reg178])
2610 margin[reg178] = curmargin;
2611 }
2612 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2613 u16 weight;
2614 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2615 sum += weight * reg178;
2616 count += weight;
2617 }
2618 }
2619 dump_timings(info);
2620 if (count == 0)
2621 die("Couldn't discover DRAM timings (3)\n");
2622
2623 u8 threshold;
2624
2625 for (threshold = 30; threshold >= 5; threshold--) {
2626 int usable_length = 0;
2627 int smallest_fount = 0;
2628 for (reg178 = reg178_min[info->clock_speed_index];
2629 reg178 < reg178_max[info->clock_speed_index];
2630 reg178 += reg178_step[info->clock_speed_index])
2631 if (margin[reg178] >= threshold) {
2632 usable_length +=
2633 reg178_step[info->clock_speed_index];
2634 info->training.reg178_largest =
2635 reg178 -
2636 2 * reg178_step[info->clock_speed_index];
2637
2638 if (!smallest_fount) {
2639 smallest_fount = 1;
2640 info->training.reg178_smallest =
2641 reg178 +
2642 reg178_step[info->
2643 clock_speed_index];
2644 }
2645 }
2646 if (usable_length >= 0x21)
2647 break;
2648 }
2649
2650 return sum / count;
2651}
2652
2653static int check_cached_sanity(struct raminfo *info)
2654{
2655 int lane;
2656 int slot, rank;
2657 int channel;
2658
2659 if (!info->cached_training)
2660 return 0;
2661
2662 for (channel = 0; channel < NUM_CHANNELS; channel++)
2663 for (slot = 0; slot < NUM_SLOTS; slot++)
2664 for (rank = 0; rank < NUM_RANKS; rank++)
2665 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2666 u16 cached_value, estimation_value;
2667 cached_value =
2668 info->cached_training->
2669 lane_timings[1][channel][slot][rank]
2670 [lane];
2671 if (cached_value >= 0x18
2672 && cached_value <= 0x1E7) {
2673 estimation_value =
2674 info->training.
2675 lane_timings[1][channel]
2676 [slot][rank][lane];
2677 if (estimation_value <
2678 cached_value - 24)
2679 return 0;
2680 if (estimation_value >
2681 cached_value + 24)
2682 return 0;
2683 }
2684 }
2685 return 1;
2686}
2687
2688static int try_cached_training(struct raminfo *info)
2689{
2690 u8 saved_243[2];
2691 u8 tm;
2692
2693 int channel, slot, rank, lane;
2694 int flip = 1;
2695 int i, j;
2696
2697 if (!check_cached_sanity(info))
2698 return 0;
2699
2700 info->training.reg178_center = info->cached_training->reg178_center;
2701 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2702 info->training.reg178_largest = info->cached_training->reg178_largest;
2703 memcpy(&info->training.timing_bounds,
2704 &info->cached_training->timing_bounds,
2705 sizeof(info->training.timing_bounds));
2706 memcpy(&info->training.timing_offset,
2707 &info->cached_training->timing_offset,
2708 sizeof(info->training.timing_offset));
2709
2710 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002711 saved_243[0] = mchbar_read8(0x243);
2712 saved_243[1] = mchbar_read8(0x643);
2713 mchbar_write8(0x243, saved_243[0] | 2);
2714 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002715 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002716 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002717 if (read_1d0(0x10b, 6) & 1)
2718 set_10b(info, 0);
2719 for (tm = 0; tm < 2; tm++) {
2720 int totalrank;
2721
2722 set_178(tm ? info->cached_training->reg178_largest : info->
2723 cached_training->reg178_smallest);
2724
2725 totalrank = 0;
2726 /* Check timing ranges. With i == 0 we check smallest one and with
2727 i == 1 the largest bound. With j == 0 we check that on the bound
2728 it still works whereas with j == 1 we check that just outside of
2729 bound we fail.
2730 */
2731 FOR_POPULATED_RANKS_BACKWARDS {
2732 for (i = 0; i < 2; i++) {
2733 for (lane = 0; lane < 8; lane++) {
2734 write_500(info, channel,
2735 info->cached_training->
2736 timing2_bounds[channel][slot]
2737 [rank][lane][i],
2738 get_timing_register_addr(lane,
2739 3,
2740 slot,
2741 rank),
2742 9, 1);
2743
2744 if (!i)
2745 write_500(info, channel,
2746 info->
2747 cached_training->
2748 timing2_offset
2749 [channel][slot][rank]
2750 [lane],
2751 get_timing_register_addr
2752 (lane, 2, slot, rank),
2753 9, 1);
2754 write_500(info, channel,
2755 i ? info->cached_training->
2756 timing_bounds[tm][channel]
2757 [slot][rank][lane].
2758 largest : info->
2759 cached_training->
2760 timing_bounds[tm][channel]
2761 [slot][rank][lane].smallest,
2762 get_timing_register_addr(lane,
2763 0,
2764 slot,
2765 rank),
2766 9, 1);
2767 write_500(info, channel,
2768 info->cached_training->
2769 timing_offset[channel][slot]
2770 [rank][lane] +
2771 (i ? info->cached_training->
2772 timing_bounds[tm][channel]
2773 [slot][rank][lane].
2774 largest : info->
2775 cached_training->
2776 timing_bounds[tm][channel]
2777 [slot][rank][lane].
2778 smallest) - 64,
2779 get_timing_register_addr(lane,
2780 1,
2781 slot,
2782 rank),
2783 9, 1);
2784 }
2785 for (j = 0; j < 2; j++) {
2786 u8 failmask;
2787 u8 expected_failmask;
2788 char reg1b3;
2789
2790 reg1b3 = (j == 1) + 4;
2791 reg1b3 =
2792 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2793 write_1d0(reg1b3, 0x1bb, 6, 1);
2794 write_1d0(reg1b3, 0x1b3, 6, 1);
2795 write_1d0(reg1b3, 0x1a3, 6, 1);
2796
2797 flip = !flip;
2798 write_testing(info, totalrank, flip);
2799 failmask =
2800 check_testing(info, totalrank,
2801 flip);
2802 expected_failmask =
2803 j == 0 ? 0x00 : 0xff;
2804 if (failmask != expected_failmask)
2805 goto fail;
2806 }
2807 }
2808 totalrank++;
2809 }
2810 }
2811
2812 set_178(info->cached_training->reg178_center);
2813 if (info->use_ecc)
2814 set_ecc(1);
2815 write_training_data(info);
2816 write_1d0(0, 322, 3, 1);
2817 info->training = *info->cached_training;
2818
2819 write_1d0(0, 0x1bb, 6, 1);
2820 write_1d0(0, 0x1b3, 6, 1);
2821 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002822 mchbar_write8(0x243, saved_243[0]);
2823 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002824
2825 return 1;
2826
2827fail:
2828 FOR_POPULATED_RANKS {
2829 write_500_timings_type(info, channel, slot, rank, 1);
2830 write_500_timings_type(info, channel, slot, rank, 2);
2831 write_500_timings_type(info, channel, slot, rank, 3);
2832 }
2833
2834 write_1d0(0, 0x1bb, 6, 1);
2835 write_1d0(0, 0x1b3, 6, 1);
2836 write_1d0(0, 0x1a3, 6, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002837 mchbar_write8(0x243, saved_243[0]);
2838 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002839
2840 return 0;
2841}
2842
2843static void do_ram_training(struct raminfo *info)
2844{
2845 u8 saved_243[2];
2846 int totalrank = 0;
2847 u8 reg_178;
2848 int niter;
2849
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002850 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002851 int lane, rank, slot, channel;
2852 u8 reg178_center;
2853
2854 write_1d0(2, 0x142, 3, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01002855 saved_243[0] = mchbar_read8(0x243);
2856 saved_243[1] = mchbar_read8(0x643);
2857 mchbar_write8(0x243, saved_243[0] | 2);
2858 mchbar_write8(0x643, saved_243[1] | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002859 switch (info->clock_speed_index) {
2860 case 0:
2861 niter = 5;
2862 break;
2863 case 1:
2864 niter = 10;
2865 break;
2866 default:
2867 niter = 19;
2868 break;
2869 }
2870 set_ecc(0);
2871
2872 FOR_POPULATED_RANKS_BACKWARDS {
2873 int i;
2874
2875 write_500_timings_type(info, channel, slot, rank, 0);
2876
2877 write_testing(info, totalrank, 0);
2878 for (i = 0; i < niter; i++) {
2879 write_testing_type2(info, totalrank, 2, i, 0);
2880 write_testing_type2(info, totalrank, 3, i, 1);
2881 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002882 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002883 totalrank++;
2884 }
2885
2886 if (reg178_min[info->clock_speed_index] <
2887 reg178_max[info->clock_speed_index])
2888 memset(timings[reg178_min[info->clock_speed_index]], 0,
2889 sizeof(timings[0]) *
2890 (reg178_max[info->clock_speed_index] -
2891 reg178_min[info->clock_speed_index]));
2892 for (reg_178 = reg178_min[info->clock_speed_index];
2893 reg_178 < reg178_max[info->clock_speed_index];
2894 reg_178 += reg178_step[info->clock_speed_index]) {
2895 totalrank = 0;
2896 set_178(reg_178);
2897 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2898 for (slot = 0; slot < NUM_SLOTS; slot++)
2899 for (rank = 0; rank < NUM_RANKS; rank++) {
2900 memset(&timings[reg_178][channel][slot]
2901 [rank][0].smallest, 0, 16);
2902 if (info->
2903 populated_ranks[channel][slot]
2904 [rank]) {
2905 train_ram_at_178(info, channel,
2906 slot, rank,
2907 totalrank,
2908 reg_178, 1,
2909 niter,
2910 timings);
2911 totalrank++;
2912 }
2913 }
2914 }
2915
2916 reg178_center = choose_reg178(info, timings);
2917
2918 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2919 info->training.timing_bounds[0][channel][slot][rank][lane].
2920 smallest =
2921 timings[info->training.
2922 reg178_smallest][channel][slot][rank][lane].
2923 smallest;
2924 info->training.timing_bounds[0][channel][slot][rank][lane].
2925 largest =
2926 timings[info->training.
2927 reg178_smallest][channel][slot][rank][lane].largest;
2928 info->training.timing_bounds[1][channel][slot][rank][lane].
2929 smallest =
2930 timings[info->training.
2931 reg178_largest][channel][slot][rank][lane].smallest;
2932 info->training.timing_bounds[1][channel][slot][rank][lane].
2933 largest =
2934 timings[info->training.
2935 reg178_largest][channel][slot][rank][lane].largest;
2936 info->training.timing_offset[channel][slot][rank][lane] =
2937 info->training.lane_timings[1][channel][slot][rank][lane]
2938 -
2939 info->training.lane_timings[0][channel][slot][rank][lane] +
2940 64;
2941 }
2942
2943 if (info->silicon_revision == 1
2944 && (info->
2945 populated_ranks_mask[1] ^ (info->
2946 populated_ranks_mask[1] >> 2)) & 1) {
2947 int ranks_after_channel1;
2948
2949 totalrank = 0;
2950 for (reg_178 = reg178_center - 18;
2951 reg_178 <= reg178_center + 18; reg_178 += 18) {
2952 totalrank = 0;
2953 set_178(reg_178);
2954 for (slot = 0; slot < NUM_SLOTS; slot++)
2955 for (rank = 0; rank < NUM_RANKS; rank++) {
2956 if (info->
2957 populated_ranks[1][slot][rank]) {
2958 train_ram_at_178(info, 1, slot,
2959 rank,
2960 totalrank,
2961 reg_178, 0,
2962 niter,
2963 timings);
2964 totalrank++;
2965 }
2966 }
2967 }
2968 ranks_after_channel1 = totalrank;
2969
2970 for (reg_178 = reg178_center - 12;
2971 reg_178 <= reg178_center + 12; reg_178 += 12) {
2972 totalrank = ranks_after_channel1;
2973 set_178(reg_178);
2974 for (slot = 0; slot < NUM_SLOTS; slot++)
2975 for (rank = 0; rank < NUM_RANKS; rank++)
2976 if (info->
2977 populated_ranks[0][slot][rank]) {
2978 train_ram_at_178(info, 0, slot,
2979 rank,
2980 totalrank,
2981 reg_178, 0,
2982 niter,
2983 timings);
2984 totalrank++;
2985 }
2986
2987 }
2988 } else {
2989 for (reg_178 = reg178_center - 12;
2990 reg_178 <= reg178_center + 12; reg_178 += 12) {
2991 totalrank = 0;
2992 set_178(reg_178);
2993 FOR_POPULATED_RANKS_BACKWARDS {
2994 train_ram_at_178(info, channel, slot, rank,
2995 totalrank, reg_178, 0, niter,
2996 timings);
2997 totalrank++;
2998 }
2999 }
3000 }
3001
3002 set_178(reg178_center);
3003 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3004 u16 tm0;
3005
3006 tm0 =
3007 choose_training(info, channel, slot, rank, lane, timings,
3008 reg178_center);
3009 write_500(info, channel, tm0,
3010 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3011 write_500(info, channel,
3012 tm0 +
3013 info->training.
3014 lane_timings[1][channel][slot][rank][lane] -
3015 info->training.
3016 lane_timings[0][channel][slot][rank][lane],
3017 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3018 }
3019
3020 totalrank = 0;
3021 FOR_POPULATED_RANKS_BACKWARDS {
3022 try_timing_offsets(info, channel, slot, rank, totalrank);
3023 totalrank++;
3024 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003025 mchbar_write8(0x243, saved_243[0]);
3026 mchbar_write8(0x643, saved_243[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003027 write_1d0(0, 0x142, 3, 1);
3028 info->training.reg178_center = reg178_center;
3029}
3030
3031static void ram_training(struct raminfo *info)
3032{
3033 u16 saved_fc4;
3034
Angel Ponsdea722b2021-03-26 14:11:12 +01003035 saved_fc4 = mchbar_read16(0xfc4);
3036 mchbar_write16(0xfc4, 0xffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003037
3038 if (info->revision >= 8)
3039 read_4090(info);
3040
3041 if (!try_cached_training(info))
3042 do_ram_training(info);
3043 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3044 && info->clock_speed_index < 2)
3045 set_10b(info, 1);
Angel Ponsdea722b2021-03-26 14:11:12 +01003046 mchbar_write16(0xfc4, saved_fc4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003047}
3048
Angel Pons7a87c922021-01-15 22:50:41 +01003049u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003050{
3051 int slot, rank, lane;
3052 u16 ret = 0;
3053
Angel Ponsdea722b2021-03-26 14:11:12 +01003054 if ((mchbar_read8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003055 return 384;
3056
3057 if (info->revision < 8)
3058 return 256;
3059
3060 for (slot = 0; slot < NUM_SLOTS; slot++)
3061 for (rank = 0; rank < NUM_RANKS; rank++)
3062 if (info->populated_ranks[channel][slot][rank])
3063 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003064 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003065 get_timing_register_addr
3066 (lane, 0, slot,
3067 rank), 9));
3068 return ret;
3069}
3070
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003071static void dmi_setup(void)
3072{
Angel Ponsdea722b2021-03-26 14:11:12 +01003073 gav(dmibar_read8(0x254));
3074 dmibar_write8(0x254, 1 << 0);
3075 dmibar_write16(0x1b8, 0x18f2);
3076 mchbar_clrsetbits16(0x48, ~0, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003077
Angel Ponsdea722b2021-03-26 14:11:12 +01003078 dmibar_setbits32(0xd68, 1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003079
3080 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3081 DEFAULT_GPIOBASE | 0x38);
3082 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3083}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003084
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003085void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003086{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003087 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003088 u16 ggc;
3089 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003090
Angel Ponsdea722b2021-03-26 14:11:12 +01003091 x2ca8 = mchbar_read8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003092 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3093 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Angel Ponsdea722b2021-03-26 14:11:12 +01003094 mchbar_write8(0x2ca8, 0);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003095 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003096 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003097
3098 dmi_setup();
3099
Angel Ponsdea722b2021-03-26 14:11:12 +01003100 mchbar_write16(0x1170, 0xa880);
3101 mchbar_write8(0x11c1, 1 << 0);
3102 mchbar_write16(0x1170, 0xb880);
3103 mchbar_clrsetbits8(0x1210, ~0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003104
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003105 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3106 /* 0 for 32MB */
3107 gfxsize = 0;
3108 }
3109
3110 ggc = 0xb00 | ((gfxsize + 5) << 4);
3111
Angel Pons16fe1e02020-07-22 16:12:33 +02003112 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003113
3114 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003115 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003116
3117 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003118 mchbar_write8(0x2c30, 1 << 5);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003119 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Angel Ponsdea722b2021-03-26 14:11:12 +01003120 mchbar_setbits16(0x2c30, 1 << 9);
3121 mchbar_write16(0x2c32, 0x434);
3122 mchbar_clrsetbits32(0x2c44, ~0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003123 pci_read_config8(GMA, MSAC); // = 0x2
3124 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003125 RCBA8(0x2318);
3126 RCBA8(0x2318) = 0x47;
3127 RCBA8(0x2320);
3128 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003129 }
3130
Angel Ponsdea722b2021-03-26 14:11:12 +01003131 mchbar_clrsetbits32(0x30, ~0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003132
Angel Pons16fe1e02020-07-22 16:12:33 +02003133 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003134 gav(RCBA32(0x3428));
3135 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003136}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003137
Angel Pons26681912021-01-15 21:36:28 +01003138static u8 get_bits_420(const u32 reg32)
3139{
3140 u8 val = 0;
3141 val |= (reg32 >> 4) & (1 << 0);
3142 val |= (reg32 >> 2) & (1 << 1);
3143 val |= (reg32 >> 0) & (1 << 2);
3144 return val;
3145}
3146
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003147void raminit(const int s3resume, const u8 *spd_addrmap)
3148{
Martin Roth468d02c2019-10-23 21:44:42 -06003149 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003150 struct raminfo info;
3151 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003152 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003153
Angel Ponsdea722b2021-03-26 14:11:12 +01003154 x2ca8 = mchbar_read8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003155
3156 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3157
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003158 memset(&info, 0x5a, sizeof(info));
3159
3160 info.last_500_command[0] = 0;
3161 info.last_500_command[1] = 0;
3162
3163 info.fsb_frequency = 135 * 2;
3164 info.board_lane_delay[0] = 0x14;
3165 info.board_lane_delay[1] = 0x07;
3166 info.board_lane_delay[2] = 0x07;
3167 info.board_lane_delay[3] = 0x08;
3168 info.board_lane_delay[4] = 0x56;
3169 info.board_lane_delay[5] = 0x04;
3170 info.board_lane_delay[6] = 0x04;
3171 info.board_lane_delay[7] = 0x05;
3172 info.board_lane_delay[8] = 0x10;
3173
3174 info.training.reg_178 = 0;
3175 info.training.reg_10b = 0;
3176
Angel Ponsa3868292021-01-15 22:10:13 +01003177 /* Wait for some bit, maybe TXT clear. */
3178 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3179 ;
3180
3181 /* Wait for ME to be ready */
Angel Pons44479962021-02-24 23:08:27 +01003182 if (intel_early_me_init() == 0)
3183 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
3184 else
3185 info.memory_reserved_for_heci_mb = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003186
3187 /* before SPD */
3188 timestamp_add_now(101);
3189
Felix Held29a9c072018-07-29 01:34:45 +02003190 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003191 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3192
3193 info.use_ecc = 1;
3194 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003195 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003196 int v;
3197 int try;
3198 int addr;
3199 const u8 useful_addresses[] = {
3200 DEVICE_TYPE,
3201 MODULE_TYPE,
3202 DENSITY,
3203 RANKS_AND_DQ,
3204 MEMORY_BUS_WIDTH,
3205 TIMEBASE_DIVIDEND,
3206 TIMEBASE_DIVISOR,
3207 CYCLETIME,
3208 CAS_LATENCIES_LSB,
3209 CAS_LATENCIES_MSB,
3210 CAS_LATENCY_TIME,
3211 0x11, 0x12, 0x13, 0x14, 0x15,
3212 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3213 0x1c, 0x1d,
3214 THERMAL_AND_REFRESH,
3215 0x20,
3216 REFERENCE_RAW_CARD_USED,
3217 RANK1_ADDRESS_MAPPING,
3218 0x75, 0x76, 0x77, 0x78,
3219 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3220 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3221 0x85, 0x86, 0x87, 0x88,
3222 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3223 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3224 0x95
3225 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003226 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003227 continue;
3228 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003229 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003230 DEVICE_TYPE);
3231 if (v >= 0)
3232 break;
3233 }
3234 if (v < 0)
3235 continue;
3236 for (addr = 0;
3237 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003238 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003239 gav(info.
3240 spd[channel][0][useful_addresses
3241 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003242 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003243 useful_addresses
3244 [addr]));
3245 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3246 die("Only DDR3 is supported");
3247
3248 v = info.spd[channel][0][RANKS_AND_DQ];
3249 info.populated_ranks[channel][0][0] = 1;
3250 info.populated_ranks[channel][0][1] =
3251 ((v >> 3) & 7);
3252 if (((v >> 3) & 7) > 1)
3253 die("At most 2 ranks are supported");
3254 if ((v & 7) == 0 || (v & 7) > 2)
3255 die("Only x8 and x16 modules are supported");
3256 if ((info.
3257 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3258 && (info.
3259 spd[channel][slot][MODULE_TYPE] & 0xF)
3260 != 3)
3261 die("Registered memory is not supported");
3262 info.is_x16_module[channel][0] = (v & 7) - 1;
3263 info.density[channel][slot] =
3264 info.spd[channel][slot][DENSITY] & 0xF;
3265 if (!
3266 (info.
3267 spd[channel][slot][MEMORY_BUS_WIDTH] &
3268 0x18))
3269 info.use_ecc = 0;
3270 }
3271
3272 gav(0x55);
3273
3274 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3275 int v = 0;
3276 for (slot = 0; slot < NUM_SLOTS; slot++)
3277 for (rank = 0; rank < NUM_RANKS; rank++)
3278 v |= info.
3279 populated_ranks[channel][slot][rank]
3280 << (2 * slot + rank);
3281 info.populated_ranks_mask[channel] = v;
3282 }
3283
3284 gav(0x55);
3285
Angel Pons16fe1e02020-07-22 16:12:33 +02003286 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003287 }
3288
3289 /* after SPD */
3290 timestamp_add_now(102);
3291
Angel Ponsdea722b2021-03-26 14:11:12 +01003292 mchbar_clrbits8(0x2ca8, 1 << 1 | 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003293
3294 collect_system_info(&info);
3295 calculate_timings(&info);
3296
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003297 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003298 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003299 if (x2ca8 == 0 && (reg8 & 0x80)) {
3300 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3301 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3302 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3303 */
3304
3305 /* Clear bit7. */
3306
3307 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3308 (reg8 & ~(1 << 7)));
3309
3310 printk(BIOS_INFO,
3311 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003312 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003313 }
3314 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003315
3316 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003317 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3318 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003319
3320 compute_derived_timings(&info);
3321
Angel Pons56823f52021-01-16 11:27:33 +01003322 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003323
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003324 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003325
Angel Pons7a87c922021-01-15 22:50:41 +01003326 if (x2ca8 == 0)
3327 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003328
Angel Ponsdea722b2021-03-26 14:11:12 +01003329 mchbar_setbits32(0x2c80, 1 << 24);
3330 mchbar_write32(0x1804, mchbar_read32(0x1c04) & ~(1 << 27));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003331
Angel Ponsdea722b2021-03-26 14:11:12 +01003332 mchbar_read8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003333
3334 if (x2ca8 == 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003335 mchbar_clrbits8(0x2ca8, 3);
3336 mchbar_write8(0x2ca8, mchbar_read8(0x2ca8) + 4); // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003337 /* This issues a CPU reset without resetting the platform */
3338 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003339 /* Write back the S3 state to PM1_CNT to let the reset CPU
3340 know it also needs to take the s3 path. */
3341 if (s3resume)
3342 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3343 | (SLP_TYP_S3 << 10));
Angel Ponsdea722b2021-03-26 14:11:12 +01003344 mchbar_setbits32(0x1af0, 1 << 4);
Patrick Georgi546953c2014-11-29 10:38:17 +01003345 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003346 }
Angel Pons7a87c922021-01-15 22:50:41 +01003347
Angel Ponsdea722b2021-03-26 14:11:12 +01003348 mchbar_clrbits8(0x2ca8, 0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003349
Angel Ponsdea722b2021-03-26 14:11:12 +01003350 mchbar_clrbits32(0x2c80, 1 << 24);
Angel Ponsc627dc92020-09-22 17:06:44 +02003351
Angel Pons9addda32020-07-22 18:37:32 +02003352 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003353
3354 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003355 u8 x2c20 = (mchbar_read16(0x2c20) >> 8) & 3;
3356 u16 x2c10 = mchbar_read16(0x2c10);
3357 u16 value = mchbar_read16(0x2c00);
Angel Ponsc627dc92020-09-22 17:06:44 +02003358 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3359 value |= (1 << 7);
3360 else
3361 value &= ~(1 << 0);
3362
Angel Ponsdea722b2021-03-26 14:11:12 +01003363 mchbar_write16(0x2c00, value);
Angel Ponsc627dc92020-09-22 17:06:44 +02003364 }
3365
3366 udelay(1000); // !!!!
3367
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003368 write_1d0(0, 0x33d, 0, 0);
3369 write_500(&info, 0, 0, 0xb61, 0, 0);
3370 write_500(&info, 1, 0, 0xb61, 0, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01003371 mchbar_write32(0x1a30, 0);
3372 mchbar_write32(0x1a34, 0);
3373 mchbar_write16(0x614, 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3374 (info.populated_ranks[0][0][0] * 0xa0));
3375 mchbar_write16(0x616, 0x26a);
3376 mchbar_write32(0x134, 0x856000);
3377 mchbar_write32(0x160, 0x5ffffff);
3378 mchbar_clrsetbits32(0x114, ~0, 0xc2024440); // !!!!
3379 mchbar_clrsetbits32(0x118, ~0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003380 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003381 mchbar_write32(0x260 + (channel << 10), 0x30809ff |
3382 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003383 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003384 mchbar_write16(0x31c + (channel << 10), 0x101);
3385 mchbar_write16(0x360 + (channel << 10), 0x909);
3386 mchbar_write16(0x3a4 + (channel << 10), 0x101);
3387 mchbar_write16(0x3e8 + (channel << 10), 0x101);
3388 mchbar_write32(0x320 + (channel << 10), 0x29002900);
3389 mchbar_write32(0x324 + (channel << 10), 0);
3390 mchbar_write32(0x368 + (channel << 10), 0x32003200);
3391 mchbar_write16(0x352 + (channel << 10), 0x505);
3392 mchbar_write16(0x354 + (channel << 10), 0x3c3c);
3393 mchbar_write16(0x356 + (channel << 10), 0x1040);
3394 mchbar_write16(0x39a + (channel << 10), 0x73e4);
3395 mchbar_write16(0x3de + (channel << 10), 0x77ed);
3396 mchbar_write16(0x422 + (channel << 10), 0x1040);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003397 }
3398
3399 write_1d0(0x4, 0x151, 4, 1);
3400 write_1d0(0, 0x142, 3, 1);
3401 rdmsr(0x1ac); // !!!!
3402 write_500(&info, 1, 1, 0x6b3, 4, 1);
3403 write_500(&info, 1, 1, 0x6cf, 4, 1);
3404
Angel Pons244f4552021-01-15 20:41:36 +01003405 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406
3407 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3408 populated_ranks[0]
3409 [0][0]) << 0),
3410 0x1d1, 3, 1);
3411 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003412 mchbar_write16(0x38e + (channel << 10), 0x5f5f);
3413 mchbar_write16(0x3d2 + (channel << 10), 0x5f5f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003414 }
3415
3416 set_334(0);
3417
3418 program_base_timings(&info);
3419
Angel Ponsdea722b2021-03-26 14:11:12 +01003420 mchbar_setbits8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003421
3422 write_1d0(0x2, 0x1d5, 2, 1);
3423 write_1d0(0x20, 0x166, 7, 1);
3424 write_1d0(0x0, 0xeb, 3, 1);
3425 write_1d0(0x0, 0xf3, 6, 1);
3426
Angel Pons3d357562021-01-16 14:46:45 +01003427 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3428 u8 a = 0;
3429 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3430 a = 3;
3431 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3432 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003433
Angel Pons3d357562021-01-16 14:46:45 +01003434 for (lane = 0; lane < 9; lane++) {
3435 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3436 rmw_500(&info, channel, addr, 6, 0xf, a);
3437 }
3438 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003440 if (s3resume) {
3441 if (info.cached_training == NULL) {
3442 u32 reg32;
3443 printk(BIOS_ERR,
3444 "Couldn't find training data. Rebooting\n");
3445 reg32 = inl(DEFAULT_PMBASE + 0x04);
3446 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003447 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448 }
3449 int tm;
3450 info.training = *info.cached_training;
3451 for (tm = 0; tm < 4; tm++)
3452 for (channel = 0; channel < NUM_CHANNELS; channel++)
3453 for (slot = 0; slot < NUM_SLOTS; slot++)
3454 for (rank = 0; rank < NUM_RANKS; rank++)
3455 for (lane = 0; lane < 9; lane++)
3456 write_500(&info,
3457 channel,
3458 info.training.
3459 lane_timings
3460 [tm][channel]
3461 [slot][rank]
3462 [lane],
3463 get_timing_register_addr
3464 (lane, tm,
3465 slot, rank),
3466 9, 0);
3467 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3468 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3469 }
3470
Angel Ponsdea722b2021-03-26 14:11:12 +01003471 mchbar_clrsetbits32(0x1f4, ~0, 1 << 17); // !!!!
3472 mchbar_write32(0x1f0, 0x1d000200);
3473 mchbar_setbits8(0x1f0, 1 << 0);
3474 while (mchbar_read8(0x1f0) & 1)
Angel Ponsc627dc92020-09-22 17:06:44 +02003475 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003476
3477 program_board_delay(&info);
3478
Angel Ponsdea722b2021-03-26 14:11:12 +01003479 mchbar_write8(0x5ff, 0);
3480 mchbar_write8(0x5ff, 1 << 7);
3481 mchbar_write8(0x5f4, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003482
Angel Ponsdea722b2021-03-26 14:11:12 +01003483 mchbar_clrbits32(0x130, 1 << 1); // | 2 when ?
3484 while (mchbar_read32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003485 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003486
3487 rmw_1d0(0x14b, 0x47, 0x30, 7);
3488 rmw_1d0(0xd6, 0x38, 7, 6);
3489 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003490
3491 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003492 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493
Angel Ponsc627dc92020-09-22 17:06:44 +02003494 rmw_1d0(0x116, 0xe, 0, 4);
3495 rmw_1d0(0xae, 0x3e, 0, 6);
3496 rmw_1d0(0x300, 0x3e, 0, 6);
Angel Ponsdea722b2021-03-26 14:11:12 +01003497 mchbar_clrbits16(0x356, 1 << 15);
3498 mchbar_clrbits16(0x756, 1 << 15);
3499 mchbar_clrbits32(0x140, 7 << 24);
3500 mchbar_clrbits32(0x138, 7 << 24);
3501 mchbar_write32(0x130, 0x31111301);
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003502 /* Wait until REG130b0 is 1. */
Angel Ponsdea722b2021-03-26 14:11:12 +01003503 while (mchbar_read32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003505
Angel Pons26681912021-01-15 21:36:28 +01003506 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003507 {
Angel Pons26681912021-01-15 21:36:28 +01003508 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3509 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3510 value_a1 = val_xa1;
3511 rmw_1d0(0x320, 0x38, val_2f3, 6);
3512 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3513 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514 }
3515
3516 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003517 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003518
Angel Pons244f4552021-01-15 20:41:36 +01003519 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003520 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003521 if ((mchbar_read32(0x144) & 0x1f) < 0x13)
Angel Pons26681912021-01-15 21:36:28 +01003522 value_a1 += 2;
3523 else
3524 value_a1 += 1;
3525
3526 if (value_a1 > 7)
3527 value_a1 = 7;
3528
3529 write_1d0(2, 0xae, 6, 1);
3530 write_1d0(2, 0x300, 6, 1);
3531 write_1d0(value_a1, 0x121, 3, 1);
3532 rmw_1d0(0xd6, 0x38, 4, 6);
3533 rmw_1d0(0x328, 0x38, 4, 6);
3534 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003535
3536 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003537 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003538
Angel Ponsdea722b2021-03-26 14:11:12 +01003539 mchbar_write32(0x130, 0x11111301 | info.populated_ranks[1][0][0] << 30 |
3540 info.populated_ranks[0][0][0] << 29);
3541 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003542 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003543
3544 {
Angel Pons26681912021-01-15 21:36:28 +01003545 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003546 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3547 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003548 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003549 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003550
3551 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003552 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003553
3554 set_334(1);
3555
Angel Ponsdea722b2021-03-26 14:11:12 +01003556 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003557
3558 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3559 write_500(&info, channel,
3560 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3561 1);
3562 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3563 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003564 mchbar_clrsetbits32(0x2d0, ~0xff0c01ff, 0x200000);
3565 mchbar_write16(0x6c0, 0x14a0);
3566 mchbar_clrsetbits32(0x6d0, ~0xff0000ff, 0x8000);
3567 mchbar_write16(0x232, 1 << 3);
Felix Held04be2dd2018-07-29 04:53:22 +02003568 /* 0x40004 or 0 depending on ? */
Angel Ponsdea722b2021-03-26 14:11:12 +01003569 mchbar_clrsetbits32(0x234, 0x40004, 0x40004);
3570 mchbar_clrsetbits32(0x34, 0x7, 5);
3571 mchbar_write32(0x128, 0x2150d05);
3572 mchbar_write8(0x12c, 0x1f);
3573 mchbar_write8(0x12d, 0x56);
3574 mchbar_write8(0x12e, 0x31);
3575 mchbar_write8(0x12f, 0);
3576 mchbar_write8(0x271, 1 << 1);
3577 mchbar_write8(0x671, 1 << 1);
3578 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003580 mchbar_write32(0x294 + (channel << 10),
3581 (info.populated_ranks_mask[channel] & 3) << 16);
3582 mchbar_clrsetbits32(0x134, ~0xfc01ffff, 0x10000);
3583 mchbar_clrsetbits32(0x134, ~0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003584 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003585 mchbar_clrsetbits32(0x260 + (channel << 10), 0xf << 20, 1 << 27 |
3586 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003587
3588 if (!s3resume)
3589 jedec_init(&info);
3590
3591 int totalrank = 0;
3592 for (channel = 0; channel < NUM_CHANNELS; channel++)
3593 for (slot = 0; slot < NUM_SLOTS; slot++)
3594 for (rank = 0; rank < NUM_RANKS; rank++)
3595 if (info.populated_ranks[channel][slot][rank]) {
3596 jedec_read(&info, channel, slot, rank,
3597 totalrank, 0xa, 0x400);
3598 totalrank++;
3599 }
3600
Angel Ponsdea722b2021-03-26 14:11:12 +01003601 mchbar_write8(0x12c, 0x9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003602
Angel Ponsdea722b2021-03-26 14:11:12 +01003603 mchbar_clrsetbits8(0x271, 0x3e, 0x0e);
3604 mchbar_clrsetbits8(0x671, 0x3e, 0x0e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605
3606 if (!s3resume) {
3607 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003608 mchbar_write32(0x294 + (channel << 10),
3609 (info.populated_ranks_mask[channel] & 3) << 16);
3610 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003611 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003612 info.populated_ranks[channel][0][1] << 5);
3613 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003614 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003615 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003616
3617 {
3618 u8 a, b;
Angel Ponsdea722b2021-03-26 14:11:12 +01003619 a = mchbar_read8(0x243);
3620 b = mchbar_read8(0x643);
3621 mchbar_write8(0x243, a | 2);
3622 mchbar_write8(0x643, b | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623 }
3624
3625 write_1d0(7, 0x19b, 3, 1);
3626 write_1d0(7, 0x1c0, 3, 1);
3627 write_1d0(4, 0x1c6, 4, 1);
3628 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003629 rmw_1d0(0x151, 0xf, 0x4, 4);
Angel Ponsdea722b2021-03-26 14:11:12 +01003630 mchbar_write32(0x584, 0xfffff);
3631 mchbar_write32(0x984, 0xfffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632
3633 for (channel = 0; channel < NUM_CHANNELS; channel++)
3634 for (slot = 0; slot < NUM_SLOTS; slot++)
3635 for (rank = 0; rank < NUM_RANKS; rank++)
3636 if (info.
3637 populated_ranks[channel][slot]
3638 [rank])
3639 config_rank(&info, s3resume,
3640 channel, slot,
3641 rank);
3642
Angel Ponsdea722b2021-03-26 14:11:12 +01003643 mchbar_write8(0x243, 1);
3644 mchbar_write8(0x643, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645 }
3646
3647 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003648 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649 write_26c(0, 0x820);
3650 write_26c(1, 0x820);
Angel Ponsdea722b2021-03-26 14:11:12 +01003651 mchbar_setbits32(0x130, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652 /* end */
3653
3654 if (s3resume) {
3655 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003656 mchbar_write32(0x294 + (channel << 10),
3657 (info.populated_ranks_mask[channel] & 3) << 16);
3658 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003659 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003660 info.populated_ranks[channel][0][1] << 5);
3661 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003663 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664 }
3665
Angel Ponsdea722b2021-03-26 14:11:12 +01003666 mchbar_clrbits32(0xfa4, 1 << 24 | 1 << 1);
3667 mchbar_write32(0xfb0, 0x2000e019);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669 /* Before training. */
3670 timestamp_add_now(103);
3671
3672 if (!s3resume)
3673 ram_training(&info);
3674
3675 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003676 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677
3678 dump_timings(&info);
3679
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680 program_modules_memory_map(&info, 0);
3681 program_total_memory_map(&info);
3682
3683 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Angel Ponsdea722b2021-03-26 14:11:12 +01003684 mchbar_write8(0x111, 0 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Angel Ponsdea722b2021-03-26 14:11:12 +01003686 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003687 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Angel Ponsdea722b2021-03-26 14:11:12 +01003688 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003690 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691
Angel Ponsdea722b2021-03-26 14:11:12 +01003692 mchbar_clrbits32(0xfac, 1 << 31);
3693 mchbar_write32(0xfb4, 0x4800);
3694 mchbar_write32(0xfb8, (info.revision < 8) ? 0x20 : 0x0);
3695 mchbar_write32(0xe94, 0x7ffff);
3696 mchbar_write32(0xfc0, 0x80002040);
3697 mchbar_write32(0xfc4, 0x701246);
3698 mchbar_clrbits8(0xfc8, 0x70);
3699 mchbar_setbits32(0xe5c, 1 << 24);
3700 mchbar_clrsetbits32(0x1a70, 3 << 20, 2 << 20);
3701 mchbar_write32(0x50, 0x700b0);
3702 mchbar_write32(0x3c, 0x10);
3703 mchbar_clrsetbits8(0x1aa8, 0x3f, 0xa);
3704 mchbar_setbits8(0xff4, 1 << 1);
3705 mchbar_clrsetbits32(0xff8, 0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706
Angel Ponsdea722b2021-03-26 14:11:12 +01003707 mchbar_write32(0xd00, IOMMU_BASE2 | 1);
3708 mchbar_write32(0xd40, IOMMU_BASE1 | 1);
3709 mchbar_write32(0xdc0, IOMMU_BASE4 | 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003711 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3712 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3713 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003714
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715 {
3716 u32 eax;
3717
3718 eax = info.fsb_frequency / 9;
Angel Ponsdea722b2021-03-26 14:11:12 +01003719 mchbar_clrsetbits32(0xfcc, 0x3ffff,
Felix Held04be2dd2018-07-29 04:53:22 +02003720 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003721 mchbar_write32(0x20, 0x33001);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003722 }
3723
3724 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003725 mchbar_clrbits32(0x220 + (channel << 10), 0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003726 if (info.max_slots_used_in_channel == 1)
Angel Ponsdea722b2021-03-26 14:11:12 +01003727 mchbar_setbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003729 mchbar_clrbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003730
Angel Ponsdea722b2021-03-26 14:11:12 +01003731 mchbar_setbits8(0x241 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003732
Felix Held04be2dd2018-07-29 04:53:22 +02003733 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003734 || info.silicon_revision == 3))
Angel Ponsdea722b2021-03-26 14:11:12 +01003735 mchbar_setbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003736 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003737 mchbar_clrbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003738 }
3739
Angel Ponsdea722b2021-03-26 14:11:12 +01003740 mchbar_setbits32(0x115, 1 << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003741
3742 {
3743 u8 al;
3744 al = 0xd;
3745 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3746 al += 2;
3747 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Angel Ponsdea722b2021-03-26 14:11:12 +01003748 mchbar_write32(0x210, al << 16 | 0x20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003749 }
3750
3751 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003752 mchbar_write32(0x288 + (channel << 10), 0x70605040);
3753 mchbar_write32(0x28c + (channel << 10), 0xfffec080);
3754 mchbar_write32(0x290 + (channel << 10), 0x282091c |
3755 (info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003756 }
3757 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003758 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003759 reg1c = epbar_read32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003760 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003761 epbar_write32(EPVC1RCAP, reg1c); // OK
3762 mchbar_read8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003763 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Angel Ponsdea722b2021-03-26 14:11:12 +01003764 mchbar_setbits8(0x1210, 1 << 1);
3765 mchbar_write32(0x1200, 0x8800440);
3766 mchbar_write32(0x1204, 0x53ff0453);
3767 mchbar_write32(0x1208, 0x19002043);
3768 mchbar_write16(0x1214, 0x320);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003769
3770 if (info.revision == 0x10 || info.revision == 0x11) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003771 mchbar_write16(0x1214, 0x220);
3772 mchbar_setbits8(0x1210, 1 << 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003773 }
3774
Angel Ponsdea722b2021-03-26 14:11:12 +01003775 mchbar_setbits8(0x1214, 1 << 2);
3776 mchbar_write8(0x120c, 1);
3777 mchbar_write8(0x1218, 3);
3778 mchbar_write8(0x121a, 3);
3779 mchbar_write8(0x121c, 3);
3780 mchbar_write16(0xc14, 0);
3781 mchbar_write16(0xc20, 0);
3782 mchbar_write32(0x1c, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003783
3784 /* revision dependent here. */
3785
Angel Ponsdea722b2021-03-26 14:11:12 +01003786 mchbar_setbits16(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003787
3788 if (info.uma_enabled)
Angel Ponsdea722b2021-03-26 14:11:12 +01003789 mchbar_setbits32(0x11f4, 1 << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003790
Angel Ponsdea722b2021-03-26 14:11:12 +01003791 mchbar_setbits16(0x1230, 1 << 15);
3792 mchbar_setbits8(0x1214, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003793
3794 u8 bl, ebpb;
3795 u16 reg_1020;
3796
Angel Ponsdea722b2021-03-26 14:11:12 +01003797 reg_1020 = mchbar_read32(0x1020); // = 0x6c733c // OK
3798 mchbar_write8(0x1070, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003799
Angel Ponsdea722b2021-03-26 14:11:12 +01003800 mchbar_write32(0x1000, 0x100);
3801 mchbar_write8(0x1007, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003802
3803 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003804 mchbar_write16(0x1018, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003805 bl = reg_1020 >> 8;
3806 ebpb = reg_1020 & 0xff;
3807 } else {
3808 ebpb = 0;
3809 bl = 8;
3810 }
3811
3812 rdmsr(0x1a2);
3813
Angel Ponsdea722b2021-03-26 14:11:12 +01003814 mchbar_write32(0x1014, 0xffffffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003815
Angel Ponsdea722b2021-03-26 14:11:12 +01003816 mchbar_write32(0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * !!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003817
Angel Ponsdea722b2021-03-26 14:11:12 +01003818 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819
Angel Ponsdea722b2021-03-26 14:11:12 +01003820 mchbar_clrsetbits8(0x123e, 0xf0, 0x60);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003821 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003822 mchbar_clrsetbits32(0x123c, 0xf << 20, 0x6 << 20);
3823 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003824 }
3825
3826 setup_heci_uma(&info);
3827
3828 if (info.uma_enabled) {
3829 u16 ax;
Angel Ponsdea722b2021-03-26 14:11:12 +01003830 mchbar_setbits32(0x11b0, 1 << 14);
3831 mchbar_setbits32(0x11b4, 1 << 14);
3832 mchbar_setbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003833
Angel Ponsdea722b2021-03-26 14:11:12 +01003834 ax = mchbar_read16(0x1190) & 0xf00; // = 0x480a // OK
3835 mchbar_write16(0x1170, ax | (mchbar_read16(0x1170) & 0x107f) | 0x4080);
3836 mchbar_setbits16(0x1170, 1 << 12);
Felix Held04be2dd2018-07-29 04:53:22 +02003837
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003838 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003839
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840 u16 ecx;
Angel Ponsdea722b2021-03-26 14:11:12 +01003841 for (ecx = 0xffff; ecx && (mchbar_read16(0x1170) & (1 << 12)); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003842 ;
Angel Ponsdea722b2021-03-26 14:11:12 +01003843 mchbar_clrbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003844 }
3845
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003846 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3847 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003848 udelay(10000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003849 mchbar_write16(0x2ca8, 1 << 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851 udelay(1000);
3852 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003853 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3854
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003855 if (!s3resume)
3856 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003857 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003858 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003859 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003860
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003861 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003862 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003863 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003864}