blob: 9277477a8efdb88c708031918d4b299d9f4ffe3d [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;
Angel Pons2ea8b942021-12-19 17:15:48 +0100795 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +0100796 mchbar_write32(0x244 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +0200797 ((info->revision < 8) ? 1 : 0x200) |
798 ((2 - info->max_slots_used_in_channel) << 17) |
799 (channel << 21) |
Angel Ponsdea722b2021-03-26 14:11:12 +0100800 (info->some_delay_1_cycle_floor << 18) | 0x9510);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100801 if (info->max_slots_used_in_channel == 1) {
802 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
803 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
804 } else {
805 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
806 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
807 || (count_ranks_in_channel(info, 1) ==
808 2)) ? 2 : 3;
809 }
810 for (channel = 0; channel < NUM_CHANNELS; channel++) {
811 int max_of_unk;
812 int min_of_unk_2;
813
814 int i, count;
815 int sum;
816
817 if (!info->populated_ranks_mask[channel])
818 continue;
819
820 max_of_unk = 0;
821 min_of_unk_2 = 32767;
822
823 sum = 0;
824 count = 0;
825 for (i = 0; i < 3; i++) {
826 int unk1;
827 if (info->revision < 8)
828 unk1 =
829 u8_FFFD1891[0][channel][info->
830 clock_speed_index]
831 [i];
832 else if (!
833 (info->revision >= 0x10
834 || info->revision_flag_1))
835 unk1 =
836 u8_FFFD1891[1][channel][info->
837 clock_speed_index]
838 [i];
839 else
840 unk1 = 0;
841 for (slot = 0; slot < NUM_SLOTS; slot++)
842 for (rank = 0; rank < NUM_RANKS; rank++) {
843 int a = 0;
844 int b = 0;
845
846 if (!info->
847 populated_ranks[channel][slot]
848 [rank])
849 continue;
850 if (extended_silicon_revision == 4
851 && (info->
852 populated_ranks_mask[channel] &
853 5) != 5) {
854 if ((info->
855 spd[channel][slot]
856 [REFERENCE_RAW_CARD_USED] &
857 0x1F) == 3) {
858 a = u16_ffd1178[0]
859 [info->
860 clock_speed_index];
861 b = u16_fe0eb8[0][info->
862 clock_speed_index];
863 } else
864 if ((info->
865 spd[channel][slot]
866 [REFERENCE_RAW_CARD_USED]
867 & 0x1F) == 5) {
868 a = u16_ffd1178[1]
869 [info->
870 clock_speed_index];
871 b = u16_fe0eb8[1][info->
872 clock_speed_index];
873 }
874 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100875 min_of_unk_2 = MIN(min_of_unk_2, a);
876 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100877 if (rank == 0) {
878 sum += a;
879 count++;
880 }
881 {
882 int t;
883 t = b +
884 u8_FFFD0EF8[channel]
885 [extended_silicon_revision]
886 [info->
887 mode4030[channel]][info->
888 clock_speed_index];
889 if (unk1 >= t)
890 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100891 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 unk1 - t);
893 }
894 }
895 {
896 int t =
897 u8_FFFD17E0[channel]
898 [extended_silicon_revision][info->
899 mode4030
900 [channel]]
901 [info->clock_speed_index] + min_of_unk_2;
902 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100903 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100904 }
905 }
906
Jacob Garber64fb4a32019-06-10 17:29:18 -0600907 if (count == 0)
908 die("No memory ranks found for channel %u\n", channel);
909
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100910 info->avg4044[channel] = sum / count;
911 info->max4048[channel] = max_of_unk;
912 }
913}
914
915static void jedec_read(struct raminfo *info,
916 int channel, int slot, int rank,
917 int total_rank, u8 addr3, unsigned int value)
918{
919 /* Handle mirrored mapping. */
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{
Nico Huber56441322021-04-23 15:23:14 +00001692 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
Angel Pons88dcb312021-04-26 17:10:28 +02003105 gfxsize = get_uint_option("gfx_uma_size", 0); /* 0 for 32MB */
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003106
3107 ggc = 0xb00 | ((gfxsize + 5) << 4);
3108
Angel Pons16fe1e02020-07-22 16:12:33 +02003109 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003110
3111 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003112 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003113
3114 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003115 mchbar_write8(0x2c30, 1 << 5);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003116 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Angel Ponsdea722b2021-03-26 14:11:12 +01003117 mchbar_setbits16(0x2c30, 1 << 9);
3118 mchbar_write16(0x2c32, 0x434);
3119 mchbar_clrsetbits32(0x2c44, ~0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003120 pci_read_config8(GMA, MSAC); // = 0x2
3121 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003122 RCBA8(0x2318);
3123 RCBA8(0x2318) = 0x47;
3124 RCBA8(0x2320);
3125 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003126 }
3127
Angel Ponsdea722b2021-03-26 14:11:12 +01003128 mchbar_clrsetbits32(0x30, ~0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003129
Angel Pons16fe1e02020-07-22 16:12:33 +02003130 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003131 gav(RCBA32(0x3428));
3132 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003133}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003134
Angel Pons26681912021-01-15 21:36:28 +01003135static u8 get_bits_420(const u32 reg32)
3136{
3137 u8 val = 0;
3138 val |= (reg32 >> 4) & (1 << 0);
3139 val |= (reg32 >> 2) & (1 << 1);
3140 val |= (reg32 >> 0) & (1 << 2);
3141 return val;
3142}
3143
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003144void raminit(const int s3resume, const u8 *spd_addrmap)
3145{
Martin Roth468d02c2019-10-23 21:44:42 -06003146 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003147 struct raminfo info;
3148 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003149 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003150
Angel Ponsdea722b2021-03-26 14:11:12 +01003151 x2ca8 = mchbar_read8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003152
3153 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3154
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003155 memset(&info, 0x5a, sizeof(info));
3156
3157 info.last_500_command[0] = 0;
3158 info.last_500_command[1] = 0;
3159
3160 info.fsb_frequency = 135 * 2;
3161 info.board_lane_delay[0] = 0x14;
3162 info.board_lane_delay[1] = 0x07;
3163 info.board_lane_delay[2] = 0x07;
3164 info.board_lane_delay[3] = 0x08;
3165 info.board_lane_delay[4] = 0x56;
3166 info.board_lane_delay[5] = 0x04;
3167 info.board_lane_delay[6] = 0x04;
3168 info.board_lane_delay[7] = 0x05;
3169 info.board_lane_delay[8] = 0x10;
3170
3171 info.training.reg_178 = 0;
3172 info.training.reg_10b = 0;
3173
Angel Ponsa3868292021-01-15 22:10:13 +01003174 /* Wait for some bit, maybe TXT clear. */
3175 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3176 ;
3177
3178 /* Wait for ME to be ready */
Nico Huber56441322021-04-23 15:23:14 +00003179 intel_early_me_init();
3180 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003181
3182 /* before SPD */
3183 timestamp_add_now(101);
3184
Felix Held29a9c072018-07-29 01:34:45 +02003185 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003186 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3187
3188 info.use_ecc = 1;
3189 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003190 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003191 int v;
3192 int try;
3193 int addr;
3194 const u8 useful_addresses[] = {
3195 DEVICE_TYPE,
3196 MODULE_TYPE,
3197 DENSITY,
3198 RANKS_AND_DQ,
3199 MEMORY_BUS_WIDTH,
3200 TIMEBASE_DIVIDEND,
3201 TIMEBASE_DIVISOR,
3202 CYCLETIME,
3203 CAS_LATENCIES_LSB,
3204 CAS_LATENCIES_MSB,
3205 CAS_LATENCY_TIME,
3206 0x11, 0x12, 0x13, 0x14, 0x15,
3207 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3208 0x1c, 0x1d,
3209 THERMAL_AND_REFRESH,
3210 0x20,
3211 REFERENCE_RAW_CARD_USED,
3212 RANK1_ADDRESS_MAPPING,
3213 0x75, 0x76, 0x77, 0x78,
3214 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3215 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3216 0x85, 0x86, 0x87, 0x88,
3217 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3218 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3219 0x95
3220 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003221 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003222 continue;
3223 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003224 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003225 DEVICE_TYPE);
3226 if (v >= 0)
3227 break;
3228 }
3229 if (v < 0)
3230 continue;
3231 for (addr = 0;
3232 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003233 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003234 gav(info.
3235 spd[channel][0][useful_addresses
3236 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003237 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003238 useful_addresses
3239 [addr]));
3240 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3241 die("Only DDR3 is supported");
3242
3243 v = info.spd[channel][0][RANKS_AND_DQ];
3244 info.populated_ranks[channel][0][0] = 1;
3245 info.populated_ranks[channel][0][1] =
3246 ((v >> 3) & 7);
3247 if (((v >> 3) & 7) > 1)
3248 die("At most 2 ranks are supported");
3249 if ((v & 7) == 0 || (v & 7) > 2)
3250 die("Only x8 and x16 modules are supported");
3251 if ((info.
3252 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3253 && (info.
3254 spd[channel][slot][MODULE_TYPE] & 0xF)
3255 != 3)
3256 die("Registered memory is not supported");
3257 info.is_x16_module[channel][0] = (v & 7) - 1;
3258 info.density[channel][slot] =
3259 info.spd[channel][slot][DENSITY] & 0xF;
3260 if (!
3261 (info.
3262 spd[channel][slot][MEMORY_BUS_WIDTH] &
3263 0x18))
3264 info.use_ecc = 0;
3265 }
3266
3267 gav(0x55);
3268
3269 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3270 int v = 0;
3271 for (slot = 0; slot < NUM_SLOTS; slot++)
3272 for (rank = 0; rank < NUM_RANKS; rank++)
3273 v |= info.
3274 populated_ranks[channel][slot][rank]
3275 << (2 * slot + rank);
3276 info.populated_ranks_mask[channel] = v;
3277 }
3278
3279 gav(0x55);
3280
Angel Pons16fe1e02020-07-22 16:12:33 +02003281 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003282 }
3283
3284 /* after SPD */
3285 timestamp_add_now(102);
3286
Angel Ponsdea722b2021-03-26 14:11:12 +01003287 mchbar_clrbits8(0x2ca8, 1 << 1 | 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003288
3289 collect_system_info(&info);
3290 calculate_timings(&info);
3291
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003292 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003293 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003294 if (x2ca8 == 0 && (reg8 & 0x80)) {
3295 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3296 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3297 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3298 */
3299
3300 /* Clear bit7. */
3301
3302 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3303 (reg8 & ~(1 << 7)));
3304
3305 printk(BIOS_INFO,
3306 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003307 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003308 }
3309 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003310
3311 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003312 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3313 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003314
3315 compute_derived_timings(&info);
3316
Angel Pons56823f52021-01-16 11:27:33 +01003317 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003318
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003319 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003320
Angel Pons7a87c922021-01-15 22:50:41 +01003321 if (x2ca8 == 0)
3322 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003323
Angel Ponsdea722b2021-03-26 14:11:12 +01003324 mchbar_setbits32(0x2c80, 1 << 24);
3325 mchbar_write32(0x1804, mchbar_read32(0x1c04) & ~(1 << 27));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003326
Angel Ponsdea722b2021-03-26 14:11:12 +01003327 mchbar_read8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003328
3329 if (x2ca8 == 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003330 mchbar_clrbits8(0x2ca8, 3);
3331 mchbar_write8(0x2ca8, mchbar_read8(0x2ca8) + 4); // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003332 /* This issues a CPU reset without resetting the platform */
3333 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003334 /* Write back the S3 state to PM1_CNT to let the reset CPU
3335 know it also needs to take the s3 path. */
3336 if (s3resume)
3337 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3338 | (SLP_TYP_S3 << 10));
Angel Ponsdea722b2021-03-26 14:11:12 +01003339 mchbar_setbits32(0x1af0, 1 << 4);
Patrick Georgi546953c2014-11-29 10:38:17 +01003340 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003341 }
Angel Pons7a87c922021-01-15 22:50:41 +01003342
Angel Ponsdea722b2021-03-26 14:11:12 +01003343 mchbar_clrbits8(0x2ca8, 0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003344
Angel Ponsdea722b2021-03-26 14:11:12 +01003345 mchbar_clrbits32(0x2c80, 1 << 24);
Angel Ponsc627dc92020-09-22 17:06:44 +02003346
Angel Pons9addda32020-07-22 18:37:32 +02003347 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003348
3349 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003350 u8 x2c20 = (mchbar_read16(0x2c20) >> 8) & 3;
3351 u16 x2c10 = mchbar_read16(0x2c10);
3352 u16 value = mchbar_read16(0x2c00);
Angel Ponsc627dc92020-09-22 17:06:44 +02003353 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3354 value |= (1 << 7);
3355 else
3356 value &= ~(1 << 0);
3357
Angel Ponsdea722b2021-03-26 14:11:12 +01003358 mchbar_write16(0x2c00, value);
Angel Ponsc627dc92020-09-22 17:06:44 +02003359 }
3360
3361 udelay(1000); // !!!!
3362
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003363 write_1d0(0, 0x33d, 0, 0);
3364 write_500(&info, 0, 0, 0xb61, 0, 0);
3365 write_500(&info, 1, 0, 0xb61, 0, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +01003366 mchbar_write32(0x1a30, 0);
3367 mchbar_write32(0x1a34, 0);
3368 mchbar_write16(0x614, 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3369 (info.populated_ranks[0][0][0] * 0xa0));
3370 mchbar_write16(0x616, 0x26a);
3371 mchbar_write32(0x134, 0x856000);
3372 mchbar_write32(0x160, 0x5ffffff);
3373 mchbar_clrsetbits32(0x114, ~0, 0xc2024440); // !!!!
3374 mchbar_clrsetbits32(0x118, ~0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003375 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003376 mchbar_write32(0x260 + (channel << 10), 0x30809ff |
3377 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003378 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003379 mchbar_write16(0x31c + (channel << 10), 0x101);
3380 mchbar_write16(0x360 + (channel << 10), 0x909);
3381 mchbar_write16(0x3a4 + (channel << 10), 0x101);
3382 mchbar_write16(0x3e8 + (channel << 10), 0x101);
3383 mchbar_write32(0x320 + (channel << 10), 0x29002900);
3384 mchbar_write32(0x324 + (channel << 10), 0);
3385 mchbar_write32(0x368 + (channel << 10), 0x32003200);
3386 mchbar_write16(0x352 + (channel << 10), 0x505);
3387 mchbar_write16(0x354 + (channel << 10), 0x3c3c);
3388 mchbar_write16(0x356 + (channel << 10), 0x1040);
3389 mchbar_write16(0x39a + (channel << 10), 0x73e4);
3390 mchbar_write16(0x3de + (channel << 10), 0x77ed);
3391 mchbar_write16(0x422 + (channel << 10), 0x1040);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003392 }
3393
3394 write_1d0(0x4, 0x151, 4, 1);
3395 write_1d0(0, 0x142, 3, 1);
3396 rdmsr(0x1ac); // !!!!
3397 write_500(&info, 1, 1, 0x6b3, 4, 1);
3398 write_500(&info, 1, 1, 0x6cf, 4, 1);
3399
Angel Pons244f4552021-01-15 20:41:36 +01003400 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003401
3402 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3403 populated_ranks[0]
3404 [0][0]) << 0),
3405 0x1d1, 3, 1);
3406 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003407 mchbar_write16(0x38e + (channel << 10), 0x5f5f);
3408 mchbar_write16(0x3d2 + (channel << 10), 0x5f5f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003409 }
3410
3411 set_334(0);
3412
3413 program_base_timings(&info);
3414
Angel Ponsdea722b2021-03-26 14:11:12 +01003415 mchbar_setbits8(0x5ff, 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416
3417 write_1d0(0x2, 0x1d5, 2, 1);
3418 write_1d0(0x20, 0x166, 7, 1);
3419 write_1d0(0x0, 0xeb, 3, 1);
3420 write_1d0(0x0, 0xf3, 6, 1);
3421
Angel Pons3d357562021-01-16 14:46:45 +01003422 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3423 u8 a = 0;
3424 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3425 a = 3;
3426 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3427 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003428
Angel Pons3d357562021-01-16 14:46:45 +01003429 for (lane = 0; lane < 9; lane++) {
3430 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3431 rmw_500(&info, channel, addr, 6, 0xf, a);
3432 }
3433 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003434
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 if (s3resume) {
3436 if (info.cached_training == NULL) {
3437 u32 reg32;
3438 printk(BIOS_ERR,
3439 "Couldn't find training data. Rebooting\n");
3440 reg32 = inl(DEFAULT_PMBASE + 0x04);
3441 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003442 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003443 }
3444 int tm;
3445 info.training = *info.cached_training;
3446 for (tm = 0; tm < 4; tm++)
3447 for (channel = 0; channel < NUM_CHANNELS; channel++)
3448 for (slot = 0; slot < NUM_SLOTS; slot++)
3449 for (rank = 0; rank < NUM_RANKS; rank++)
3450 for (lane = 0; lane < 9; lane++)
3451 write_500(&info,
3452 channel,
3453 info.training.
3454 lane_timings
3455 [tm][channel]
3456 [slot][rank]
3457 [lane],
3458 get_timing_register_addr
3459 (lane, tm,
3460 slot, rank),
3461 9, 0);
3462 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3463 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3464 }
3465
Angel Ponsdea722b2021-03-26 14:11:12 +01003466 mchbar_clrsetbits32(0x1f4, ~0, 1 << 17); // !!!!
3467 mchbar_write32(0x1f0, 0x1d000200);
3468 mchbar_setbits8(0x1f0, 1 << 0);
3469 while (mchbar_read8(0x1f0) & 1)
Angel Ponsc627dc92020-09-22 17:06:44 +02003470 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003471
3472 program_board_delay(&info);
3473
Angel Ponsdea722b2021-03-26 14:11:12 +01003474 mchbar_write8(0x5ff, 0);
3475 mchbar_write8(0x5ff, 1 << 7);
3476 mchbar_write8(0x5f4, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003477
Angel Ponsdea722b2021-03-26 14:11:12 +01003478 mchbar_clrbits32(0x130, 1 << 1); // | 2 when ?
3479 while (mchbar_read32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003480 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003481
3482 rmw_1d0(0x14b, 0x47, 0x30, 7);
3483 rmw_1d0(0xd6, 0x38, 7, 6);
3484 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003485
3486 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003487 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003488
Angel Ponsc627dc92020-09-22 17:06:44 +02003489 rmw_1d0(0x116, 0xe, 0, 4);
3490 rmw_1d0(0xae, 0x3e, 0, 6);
3491 rmw_1d0(0x300, 0x3e, 0, 6);
Angel Ponsdea722b2021-03-26 14:11:12 +01003492 mchbar_clrbits16(0x356, 1 << 15);
3493 mchbar_clrbits16(0x756, 1 << 15);
3494 mchbar_clrbits32(0x140, 7 << 24);
3495 mchbar_clrbits32(0x138, 7 << 24);
3496 mchbar_write32(0x130, 0x31111301);
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003497 /* Wait until REG130b0 is 1. */
Angel Ponsdea722b2021-03-26 14:11:12 +01003498 while (mchbar_read32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003499 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003500
Angel Pons26681912021-01-15 21:36:28 +01003501 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003502 {
Angel Pons26681912021-01-15 21:36:28 +01003503 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3504 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3505 value_a1 = val_xa1;
3506 rmw_1d0(0x320, 0x38, val_2f3, 6);
3507 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3508 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003509 }
3510
3511 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003512 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003513
Angel Pons244f4552021-01-15 20:41:36 +01003514 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003515 {
Angel Ponsdea722b2021-03-26 14:11:12 +01003516 if ((mchbar_read32(0x144) & 0x1f) < 0x13)
Angel Pons26681912021-01-15 21:36:28 +01003517 value_a1 += 2;
3518 else
3519 value_a1 += 1;
3520
3521 if (value_a1 > 7)
3522 value_a1 = 7;
3523
3524 write_1d0(2, 0xae, 6, 1);
3525 write_1d0(2, 0x300, 6, 1);
3526 write_1d0(value_a1, 0x121, 3, 1);
3527 rmw_1d0(0xd6, 0x38, 4, 6);
3528 rmw_1d0(0x328, 0x38, 4, 6);
3529 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003530
3531 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003532 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003533
Angel Ponsdea722b2021-03-26 14:11:12 +01003534 mchbar_write32(0x130, 0x11111301 | info.populated_ranks[1][0][0] << 30 |
3535 info.populated_ranks[0][0][0] << 29);
3536 while (mchbar_read8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003537 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003538
3539 {
Angel Pons26681912021-01-15 21:36:28 +01003540 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003541 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3542 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003543 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003544 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003545
3546 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003547 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003548
3549 set_334(1);
3550
Angel Ponsdea722b2021-03-26 14:11:12 +01003551 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003552
3553 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3554 write_500(&info, channel,
3555 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3556 1);
3557 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3558 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003559 mchbar_clrsetbits32(0x2d0, ~0xff0c01ff, 0x200000);
3560 mchbar_write16(0x6c0, 0x14a0);
3561 mchbar_clrsetbits32(0x6d0, ~0xff0000ff, 0x8000);
3562 mchbar_write16(0x232, 1 << 3);
Felix Held04be2dd2018-07-29 04:53:22 +02003563 /* 0x40004 or 0 depending on ? */
Angel Ponsdea722b2021-03-26 14:11:12 +01003564 mchbar_clrsetbits32(0x234, 0x40004, 0x40004);
3565 mchbar_clrsetbits32(0x34, 0x7, 5);
3566 mchbar_write32(0x128, 0x2150d05);
3567 mchbar_write8(0x12c, 0x1f);
3568 mchbar_write8(0x12d, 0x56);
3569 mchbar_write8(0x12e, 0x31);
3570 mchbar_write8(0x12f, 0);
3571 mchbar_write8(0x271, 1 << 1);
3572 mchbar_write8(0x671, 1 << 1);
3573 mchbar_write8(0x1e8, 1 << 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003574 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003575 mchbar_write32(0x294 + (channel << 10),
3576 (info.populated_ranks_mask[channel] & 3) << 16);
3577 mchbar_clrsetbits32(0x134, ~0xfc01ffff, 0x10000);
3578 mchbar_clrsetbits32(0x134, ~0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsdea722b2021-03-26 14:11:12 +01003580 mchbar_clrsetbits32(0x260 + (channel << 10), 0xf << 20, 1 << 27 |
3581 (info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003582
3583 if (!s3resume)
3584 jedec_init(&info);
3585
3586 int totalrank = 0;
3587 for (channel = 0; channel < NUM_CHANNELS; channel++)
3588 for (slot = 0; slot < NUM_SLOTS; slot++)
3589 for (rank = 0; rank < NUM_RANKS; rank++)
3590 if (info.populated_ranks[channel][slot][rank]) {
3591 jedec_read(&info, channel, slot, rank,
3592 totalrank, 0xa, 0x400);
3593 totalrank++;
3594 }
3595
Angel Ponsdea722b2021-03-26 14:11:12 +01003596 mchbar_write8(0x12c, 0x9f);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003597
Angel Ponsdea722b2021-03-26 14:11:12 +01003598 mchbar_clrsetbits8(0x271, 0x3e, 0x0e);
3599 mchbar_clrsetbits8(0x671, 0x3e, 0x0e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003600
3601 if (!s3resume) {
3602 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003603 mchbar_write32(0x294 + (channel << 10),
3604 (info.populated_ranks_mask[channel] & 3) << 16);
3605 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003606 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003607 info.populated_ranks[channel][0][1] << 5);
3608 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003610 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611
3612 {
3613 u8 a, b;
Angel Ponsdea722b2021-03-26 14:11:12 +01003614 a = mchbar_read8(0x243);
3615 b = mchbar_read8(0x643);
3616 mchbar_write8(0x243, a | 2);
3617 mchbar_write8(0x643, b | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618 }
3619
3620 write_1d0(7, 0x19b, 3, 1);
3621 write_1d0(7, 0x1c0, 3, 1);
3622 write_1d0(4, 0x1c6, 4, 1);
3623 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003624 rmw_1d0(0x151, 0xf, 0x4, 4);
Angel Ponsdea722b2021-03-26 14:11:12 +01003625 mchbar_write32(0x584, 0xfffff);
3626 mchbar_write32(0x984, 0xfffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627
3628 for (channel = 0; channel < NUM_CHANNELS; channel++)
3629 for (slot = 0; slot < NUM_SLOTS; slot++)
3630 for (rank = 0; rank < NUM_RANKS; rank++)
3631 if (info.
3632 populated_ranks[channel][slot]
3633 [rank])
3634 config_rank(&info, s3resume,
3635 channel, slot,
3636 rank);
3637
Angel Ponsdea722b2021-03-26 14:11:12 +01003638 mchbar_write8(0x243, 1);
3639 mchbar_write8(0x643, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 }
3641
3642 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003643 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 write_26c(0, 0x820);
3645 write_26c(1, 0x820);
Angel Ponsdea722b2021-03-26 14:11:12 +01003646 mchbar_setbits32(0x130, 1 << 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647 /* end */
3648
3649 if (s3resume) {
3650 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003651 mchbar_write32(0x294 + (channel << 10),
3652 (info.populated_ranks_mask[channel] & 3) << 16);
3653 mchbar_write16(0x298 + (channel << 10),
Felix Held04be2dd2018-07-29 04:53:22 +02003654 info.populated_ranks[channel][0][0] |
Angel Ponsdea722b2021-03-26 14:11:12 +01003655 info.populated_ranks[channel][0][1] << 5);
3656 mchbar_write32(0x29c + (channel << 10), 0x77a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657 }
Angel Ponsdea722b2021-03-26 14:11:12 +01003658 mchbar_clrsetbits32(0x2c0, ~0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659 }
3660
Angel Ponsdea722b2021-03-26 14:11:12 +01003661 mchbar_clrbits32(0xfa4, 1 << 24 | 1 << 1);
3662 mchbar_write32(0xfb0, 0x2000e019);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664 /* Before training. */
3665 timestamp_add_now(103);
3666
3667 if (!s3resume)
3668 ram_training(&info);
3669
3670 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003671 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672
3673 dump_timings(&info);
3674
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675 program_modules_memory_map(&info, 0);
3676 program_total_memory_map(&info);
3677
3678 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Angel Ponsdea722b2021-03-26 14:11:12 +01003679 mchbar_write8(0x111, 0 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Angel Ponsdea722b2021-03-26 14:11:12 +01003681 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Angel Ponsdea722b2021-03-26 14:11:12 +01003683 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 0 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003684 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003685 mchbar_write8(0x111, 3 << 2 | 1 << 5 | 1 << 6 | 0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686
Angel Ponsdea722b2021-03-26 14:11:12 +01003687 mchbar_clrbits32(0xfac, 1 << 31);
3688 mchbar_write32(0xfb4, 0x4800);
3689 mchbar_write32(0xfb8, (info.revision < 8) ? 0x20 : 0x0);
3690 mchbar_write32(0xe94, 0x7ffff);
3691 mchbar_write32(0xfc0, 0x80002040);
3692 mchbar_write32(0xfc4, 0x701246);
3693 mchbar_clrbits8(0xfc8, 0x70);
3694 mchbar_setbits32(0xe5c, 1 << 24);
3695 mchbar_clrsetbits32(0x1a70, 3 << 20, 2 << 20);
3696 mchbar_write32(0x50, 0x700b0);
3697 mchbar_write32(0x3c, 0x10);
3698 mchbar_clrsetbits8(0x1aa8, 0x3f, 0xa);
3699 mchbar_setbits8(0xff4, 1 << 1);
3700 mchbar_clrsetbits32(0xff8, 0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003701
Angel Ponsdea722b2021-03-26 14:11:12 +01003702 mchbar_write32(0xd00, IOMMU_BASE2 | 1);
3703 mchbar_write32(0xd40, IOMMU_BASE1 | 1);
3704 mchbar_write32(0xdc0, IOMMU_BASE4 | 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003705
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003706 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3707 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3708 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003709
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710 {
3711 u32 eax;
3712
3713 eax = info.fsb_frequency / 9;
Angel Ponsdea722b2021-03-26 14:11:12 +01003714 mchbar_clrsetbits32(0xfcc, 0x3ffff,
Felix Held04be2dd2018-07-29 04:53:22 +02003715 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003716 mchbar_write32(0x20, 0x33001);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003717 }
3718
3719 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003720 mchbar_clrbits32(0x220 + (channel << 10), 0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003721 if (info.max_slots_used_in_channel == 1)
Angel Ponsdea722b2021-03-26 14:11:12 +01003722 mchbar_setbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003724 mchbar_clrbits16(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725
Angel Ponsdea722b2021-03-26 14:11:12 +01003726 mchbar_setbits8(0x241 + (channel << 10), 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727
Felix Held04be2dd2018-07-29 04:53:22 +02003728 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003729 || info.silicon_revision == 3))
Angel Ponsdea722b2021-03-26 14:11:12 +01003730 mchbar_setbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003731 else
Angel Ponsdea722b2021-03-26 14:11:12 +01003732 mchbar_clrbits32(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003733 }
3734
Angel Ponsdea722b2021-03-26 14:11:12 +01003735 mchbar_setbits32(0x115, 1 << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003736
3737 {
3738 u8 al;
3739 al = 0xd;
3740 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3741 al += 2;
3742 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Angel Ponsdea722b2021-03-26 14:11:12 +01003743 mchbar_write32(0x210, al << 16 | 0x20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003744 }
3745
3746 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003747 mchbar_write32(0x288 + (channel << 10), 0x70605040);
3748 mchbar_write32(0x28c + (channel << 10), 0xfffec080);
3749 mchbar_write32(0x290 + (channel << 10), 0x282091c |
3750 (info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003751 }
3752 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003753 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003754 reg1c = epbar_read32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003755 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Ponsdea722b2021-03-26 14:11:12 +01003756 epbar_write32(EPVC1RCAP, reg1c); // OK
3757 mchbar_read8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003758 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Angel Ponsdea722b2021-03-26 14:11:12 +01003759 mchbar_setbits8(0x1210, 1 << 1);
3760 mchbar_write32(0x1200, 0x8800440);
3761 mchbar_write32(0x1204, 0x53ff0453);
3762 mchbar_write32(0x1208, 0x19002043);
3763 mchbar_write16(0x1214, 0x320);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764
3765 if (info.revision == 0x10 || info.revision == 0x11) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003766 mchbar_write16(0x1214, 0x220);
3767 mchbar_setbits8(0x1210, 1 << 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003768 }
3769
Angel Ponsdea722b2021-03-26 14:11:12 +01003770 mchbar_setbits8(0x1214, 1 << 2);
3771 mchbar_write8(0x120c, 1);
3772 mchbar_write8(0x1218, 3);
3773 mchbar_write8(0x121a, 3);
3774 mchbar_write8(0x121c, 3);
3775 mchbar_write16(0xc14, 0);
3776 mchbar_write16(0xc20, 0);
3777 mchbar_write32(0x1c, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003778
3779 /* revision dependent here. */
3780
Angel Ponsdea722b2021-03-26 14:11:12 +01003781 mchbar_setbits16(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003782
3783 if (info.uma_enabled)
Angel Ponsdea722b2021-03-26 14:11:12 +01003784 mchbar_setbits32(0x11f4, 1 << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003785
Angel Ponsdea722b2021-03-26 14:11:12 +01003786 mchbar_setbits16(0x1230, 1 << 15);
3787 mchbar_setbits8(0x1214, 1 << 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003788
3789 u8 bl, ebpb;
3790 u16 reg_1020;
3791
Angel Ponsdea722b2021-03-26 14:11:12 +01003792 reg_1020 = mchbar_read32(0x1020); // = 0x6c733c // OK
3793 mchbar_write8(0x1070, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003794
Angel Ponsdea722b2021-03-26 14:11:12 +01003795 mchbar_write32(0x1000, 0x100);
3796 mchbar_write8(0x1007, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003797
3798 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003799 mchbar_write16(0x1018, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003800 bl = reg_1020 >> 8;
3801 ebpb = reg_1020 & 0xff;
3802 } else {
3803 ebpb = 0;
3804 bl = 8;
3805 }
3806
3807 rdmsr(0x1a2);
3808
Angel Ponsdea722b2021-03-26 14:11:12 +01003809 mchbar_write32(0x1014, 0xffffffff);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003810
Angel Ponsdea722b2021-03-26 14:11:12 +01003811 mchbar_write32(0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * !!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003812
Angel Ponsdea722b2021-03-26 14:11:12 +01003813 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003814
Angel Ponsdea722b2021-03-26 14:11:12 +01003815 mchbar_clrsetbits8(0x123e, 0xf0, 0x60);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003816 if (reg_1020 != 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +01003817 mchbar_clrsetbits32(0x123c, 0xf << 20, 0x6 << 20);
3818 mchbar_write8(0x101c, 0xb8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819 }
3820
3821 setup_heci_uma(&info);
3822
3823 if (info.uma_enabled) {
3824 u16 ax;
Angel Ponsdea722b2021-03-26 14:11:12 +01003825 mchbar_setbits32(0x11b0, 1 << 14);
3826 mchbar_setbits32(0x11b4, 1 << 14);
3827 mchbar_setbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003828
Angel Ponsdea722b2021-03-26 14:11:12 +01003829 ax = mchbar_read16(0x1190) & 0xf00; // = 0x480a // OK
3830 mchbar_write16(0x1170, ax | (mchbar_read16(0x1170) & 0x107f) | 0x4080);
3831 mchbar_setbits16(0x1170, 1 << 12);
Felix Held04be2dd2018-07-29 04:53:22 +02003832
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003833 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003834
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835 u16 ecx;
Angel Ponsdea722b2021-03-26 14:11:12 +01003836 for (ecx = 0xffff; ecx && (mchbar_read16(0x1170) & (1 << 12)); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003837 ;
Angel Ponsdea722b2021-03-26 14:11:12 +01003838 mchbar_clrbits16(0x1190, 1 << 14);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003839 }
3840
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003841 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3842 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003843 udelay(10000);
Angel Ponsdea722b2021-03-26 14:11:12 +01003844 mchbar_write16(0x2ca8, 1 << 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003845
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003846 udelay(1000);
3847 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003848 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3849
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003850 if (!s3resume)
3851 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003852 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003853 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003854 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003855
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003856 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003857 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003858 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859}