blob: 56cd14b45055710ca90bf0197b6337f238a53875 [file] [log] [blame]
Angel Pons7a87c922021-01-15 22:50:41 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
Angel Ponsfa5ed052021-12-18 22:25:07 +01004#include <cpu/intel/model_2065x/model_2065x.h>
5#include <cpu/x86/msr.h>
Angel Pons7a87c922021-01-15 22:50:41 +01006#include <delay.h>
7#include <device/pci_def.h>
8#include <device/pci_ops.h>
9#include <northbridge/intel/ironlake/raminit.h>
10#include <types.h>
11
12#define NORTHBRIDGE PCI_DEV(0, 0, 0)
13
14static unsigned int gcd(unsigned int a, unsigned int b)
15{
16 unsigned int t;
17 if (a > b) {
18 t = a;
19 a = b;
20 b = t;
21 }
22 /* invariant a < b. */
23 while (a) {
24 t = b % a;
25 b = a;
26 a = t;
27 }
28 return b;
29}
30
31static inline int div_roundup(int a, int b)
32{
33 return DIV_ROUND_UP(a, b);
34}
35
36static unsigned int lcm(unsigned int a, unsigned int b)
37{
38 return (a * b) / gcd(a, b);
39}
40
41struct stru1 {
42 u8 freqs_reversed;
43 u8 freq_diff_reduced;
44 u8 freq_min_reduced;
45 u8 divisor_f4_to_fmax;
46 u8 divisor_f3_to_fmax;
47 u8 freq4_to_max_remainder;
48 u8 freq3_to_2_remainder;
49 u8 freq3_to_2_remaindera;
50 u8 freq4_to_2_remainder;
51 int divisor_f3_to_f1, divisor_f4_to_f2;
52 int common_time_unit_ps;
53 int freq_max_reduced;
54};
55
56static void
57compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
58 int num_cycles_2, int num_cycles_1, int round_it,
59 int add_freqs, struct stru1 *result)
60{
61 int g;
62 int common_time_unit_ps;
63 int freq1_reduced, freq2_reduced;
64 int freq_min_reduced;
65 int freq_max_reduced;
66 int freq3, freq4;
67
68 g = gcd(freq1, freq2);
69 freq1_reduced = freq1 / g;
70 freq2_reduced = freq2 / g;
71 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
72 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
73
74 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
75 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
76 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
77 if (add_freqs) {
78 freq3 += freq2_reduced;
79 freq4 += freq1_reduced;
80 }
81
82 if (round_it) {
83 result->freq3_to_2_remainder = 0;
84 result->freq3_to_2_remaindera = 0;
85 result->freq4_to_max_remainder = 0;
86 result->divisor_f4_to_f2 = 0;
87 result->divisor_f3_to_f1 = 0;
88 } else {
89 if (freq2_reduced < freq1_reduced) {
90 result->freq3_to_2_remainder =
91 result->freq3_to_2_remaindera =
92 freq3 % freq1_reduced - freq1_reduced + 1;
93 result->freq4_to_max_remainder =
94 -(freq4 % freq1_reduced);
95 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
96 result->divisor_f4_to_f2 =
97 (freq4 -
98 (freq1_reduced - freq2_reduced)) / freq2_reduced;
99 result->freq4_to_2_remainder =
100 -(char)((freq1_reduced - freq2_reduced) +
Elyes Haouas3a998072022-11-18 15:11:02 +0100101 ((u8)freq4 -
Angel Pons7a87c922021-01-15 22:50:41 +0100102 (freq1_reduced -
Elyes Haouas3a998072022-11-18 15:11:02 +0100103 freq2_reduced)) % (u8)freq2_reduced);
Angel Pons7a87c922021-01-15 22:50:41 +0100104 } else {
105 if (freq2_reduced > freq1_reduced) {
106 result->freq4_to_max_remainder =
107 (freq4 % freq2_reduced) - freq2_reduced + 1;
108 result->freq4_to_2_remainder =
109 freq4 % freq_max_reduced -
110 freq_max_reduced + 1;
111 } else {
112 result->freq4_to_max_remainder =
113 -(freq4 % freq2_reduced);
114 result->freq4_to_2_remainder =
115 -(char)(freq4 % freq_max_reduced);
116 }
117 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
118 result->divisor_f3_to_f1 =
119 (freq3 -
120 (freq2_reduced - freq1_reduced)) / freq1_reduced;
121 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
122 result->freq3_to_2_remaindera =
123 -(char)((freq_max_reduced - freq_min_reduced) +
124 (freq3 -
125 (freq_max_reduced -
126 freq_min_reduced)) % freq1_reduced);
127 }
128 }
129 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
130 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
131 if (round_it) {
132 if (freq2_reduced > freq1_reduced) {
133 if (freq3 % freq_max_reduced)
134 result->divisor_f3_to_fmax++;
135 }
136 if (freq2_reduced < freq1_reduced) {
137 if (freq4 % freq_max_reduced)
138 result->divisor_f4_to_fmax++;
139 }
140 }
141 result->freqs_reversed = (freq2_reduced < freq1_reduced);
142 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
143 result->freq_min_reduced = freq_min_reduced;
144 result->common_time_unit_ps = common_time_unit_ps;
145 result->freq_max_reduced = freq_max_reduced;
146}
147
Angel Pons0a8b1132021-01-15 23:13:00 +0100148static void compute_274265(struct raminfo *info)
Angel Pons7a87c922021-01-15 22:50:41 +0100149{
150 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
151 int delay_e_ps, delay_e_cycles, delay_f_cycles;
152 int delay_e_over_cycle_ps;
153 int cycletime_ps;
154 int channel;
155
156 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
157 info->training.reg2ca9_bit0 = 0;
158 for (channel = 0; channel < NUM_CHANNELS; channel++) {
159 cycletime_ps =
160 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
161 delay_d_ps =
162 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
163 - info->some_delay_3_ps_rounded + 200;
164 if (!
165 ((info->silicon_revision == 0
166 || info->silicon_revision == 1)
167 && (info->revision >= 8)))
168 delay_d_ps += halfcycle_ps(info) * 2;
169 delay_d_ps +=
170 halfcycle_ps(info) * (!info->revision_flag_1 +
171 info->some_delay_2_halfcycles_ceil +
172 2 * info->some_delay_1_cycle_floor +
173 info->clock_speed_index +
174 2 * info->cas_latency - 7 + 11);
175 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
176
Angel Ponsdea722b2021-03-26 14:11:12 +0100177 mchbar_clrsetbits32(0x140, 7 << 24, 2 << 24);
178 mchbar_clrsetbits32(0x138, 7 << 24, 2 << 24);
179 if ((mchbar_read8(0x144) & 0x1f) > 0x13)
Angel Pons7a87c922021-01-15 22:50:41 +0100180 delay_d_ps += 650;
181 delay_c_ps = delay_d_ps + 1800;
182 if (delay_c_ps <= delay_a_ps)
183 delay_e_ps = 0;
184 else
185 delay_e_ps =
186 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
187 cycletime_ps);
188
189 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
190 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
191 delay_f_cycles =
192 div_roundup(2500 - delay_e_over_cycle_ps,
193 2 * halfcycle_ps(info));
194 if (delay_f_cycles > delay_e_cycles) {
195 info->delay46_ps[channel] = delay_e_ps;
196 delay_e_cycles = 0;
197 } else {
198 info->delay46_ps[channel] =
199 delay_e_over_cycle_ps +
200 2 * halfcycle_ps(info) * delay_f_cycles;
201 delay_e_cycles -= delay_f_cycles;
202 }
203
204 if (info->delay46_ps[channel] < 2500) {
205 info->delay46_ps[channel] = 2500;
206 info->training.reg2ca9_bit0 = 1;
207 }
208 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
209 if (delay_b_ps <= delay_a_ps)
210 delay_b_ps = 0;
211 else
212 delay_b_ps -= delay_a_ps;
213 info->delay54_ps[channel] =
214 cycletime_ps * div_roundup(delay_b_ps,
215 cycletime_ps) -
216 2 * halfcycle_ps(info) * delay_e_cycles;
217 if (info->delay54_ps[channel] < 2500)
218 info->delay54_ps[channel] = 2500;
219 info->training.reg274265[channel][0] = delay_e_cycles;
220 if (delay_d_ps + 7 * halfcycle_ps(info) <=
221 24 * halfcycle_ps(info))
222 info->training.reg274265[channel][1] = 0;
223 else
224 info->training.reg274265[channel][1] =
225 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
226 4 * halfcycle_ps(info)) - 6;
Angel Pons7a87c922021-01-15 22:50:41 +0100227 info->training.reg274265[channel][2] =
228 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
229 4 * halfcycle_ps(info)) + 1;
Angel Pons7a87c922021-01-15 22:50:41 +0100230 }
Angel Pons7a87c922021-01-15 22:50:41 +0100231}
232
Angel Pons0a8b1132021-01-15 23:13:00 +0100233static void program_274265(const struct ram_training *const training)
Angel Pons7a87c922021-01-15 22:50:41 +0100234{
235 int channel;
236
237 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100238 mchbar_write32((channel << 10) + 0x274,
Angel Pons0a8b1132021-01-15 23:13:00 +0100239 (training->reg274265[channel][0] << 16) |
Angel Ponsdea722b2021-03-26 14:11:12 +0100240 training->reg274265[channel][1]);
241 mchbar_write16((channel << 10) + 0x265,
242 training->reg274265[channel][2] << 8);
Angel Pons7a87c922021-01-15 22:50:41 +0100243 }
Angel Pons0a8b1132021-01-15 23:13:00 +0100244 if (training->reg2ca9_bit0)
Angel Ponsdea722b2021-03-26 14:11:12 +0100245 mchbar_setbits8(0x2ca9, 1 << 0);
Angel Pons7a87c922021-01-15 22:50:41 +0100246 else
Angel Ponsdea722b2021-03-26 14:11:12 +0100247 mchbar_clrbits8(0x2ca9, 1 << 0);
Angel Pons0a8b1132021-01-15 23:13:00 +0100248
249 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n", training->reg2ca9_bit0);
250
251 for (int i = 0; i < 2; i++)
252 for (int j = 0; j < 3; j++)
253 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
254 i, j, training->reg274265[i][j]);
Angel Pons7a87c922021-01-15 22:50:41 +0100255}
256
257static void
258set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
259 int num_cycles_2, int num_cycles_1, int num_cycles_3,
260 int num_cycles_4, int reverse)
261{
262 struct stru1 vv;
263 char multiplier;
264
265 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
266 0, 1, &vv);
267
268 multiplier =
269 div_roundup(MAX
270 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
271 div_roundup(num_cycles_3, vv.common_time_unit_ps),
272 div_roundup(num_cycles_1,
273 vv.common_time_unit_ps) +
274 div_roundup(num_cycles_4, vv.common_time_unit_ps))
275 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
276
277 u32 y =
Elyes Haouas3a998072022-11-18 15:11:02 +0100278 (u8)((vv.freq_max_reduced - vv.freq_min_reduced) +
Angel Pons7a87c922021-01-15 22:50:41 +0100279 vv.freq_max_reduced * multiplier)
280 | (vv.
Elyes Haouas3a998072022-11-18 15:11:02 +0100281 freqs_reversed << 8) | ((u8)(vv.freq_min_reduced *
282 multiplier) << 16) | ((u8)(vv.
Angel Pons7a87c922021-01-15 22:50:41 +0100283 freq_min_reduced
284 *
285 multiplier)
286 << 24);
287 u32 x =
288 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
289 divisor_f3_to_f1
290 << 16)
291 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
292 if (reverse) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100293 mchbar_write32(reg + 0, y);
294 mchbar_write32(reg + 4, x);
Angel Pons7a87c922021-01-15 22:50:41 +0100295 } else {
Angel Ponsdea722b2021-03-26 14:11:12 +0100296 mchbar_write32(reg + 4, y);
297 mchbar_write32(reg + 0, x);
Angel Pons7a87c922021-01-15 22:50:41 +0100298 }
299}
300
301static void
302set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
303 int num_cycles_1, int num_cycles_2, int num_cycles_3,
304 int num_cycles_4)
305{
306 struct stru1 ratios1;
307 struct stru1 ratios2;
308
309 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
310 0, 1, &ratios2);
311 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
312 0, 1, &ratios1);
313 printk(RAM_SPEW, "[%x] <= %x\n", reg,
314 ratios1.freq4_to_max_remainder | (ratios2.
315 freq4_to_max_remainder
316 << 8)
317 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
318 divisor_f4_to_fmax
319 << 20));
Angel Ponsdea722b2021-03-26 14:11:12 +0100320 mchbar_write32(reg, ratios1.freq4_to_max_remainder |
321 ratios2.freq4_to_max_remainder << 8 |
322 ratios1.divisor_f4_to_fmax << 16 |
323 ratios2.divisor_f4_to_fmax << 20);
Angel Pons7a87c922021-01-15 22:50:41 +0100324}
325
326static void
327set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
328 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
329{
330 struct stru1 ratios;
331
332 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
333 round_it, add_freqs, &ratios);
334 switch (mode) {
335 case 0:
Angel Ponsdea722b2021-03-26 14:11:12 +0100336 mchbar_write32(reg + 4,
337 ratios.freq_diff_reduced |
338 ratios.freqs_reversed << 8);
339 mchbar_write32(reg,
340 ratios.freq3_to_2_remainder |
341 ratios.freq4_to_max_remainder << 8 |
342 ratios.divisor_f3_to_fmax << 16 |
343 ratios.divisor_f4_to_fmax << 20 |
344 ratios.freq_min_reduced << 24);
Angel Pons7a87c922021-01-15 22:50:41 +0100345 break;
346
347 case 1:
Angel Ponsdea722b2021-03-26 14:11:12 +0100348 mchbar_write32(reg,
349 ratios.freq3_to_2_remainder |
350 ratios.divisor_f3_to_fmax << 16);
Angel Pons7a87c922021-01-15 22:50:41 +0100351 break;
352
353 case 2:
Angel Ponsdea722b2021-03-26 14:11:12 +0100354 mchbar_write32(reg,
355 ratios.freq3_to_2_remainder |
356 ratios.freq4_to_max_remainder << 8 |
357 ratios.divisor_f3_to_fmax << 16 |
358 ratios.divisor_f4_to_fmax << 20);
Angel Pons7a87c922021-01-15 22:50:41 +0100359 break;
360
361 case 4:
Angel Ponsdea722b2021-03-26 14:11:12 +0100362 mchbar_write32(reg,
363 ratios.divisor_f3_to_fmax << 4 |
364 ratios.divisor_f4_to_fmax << 8 |
365 ratios.freqs_reversed << 12 |
366 ratios.freq_min_reduced << 16 |
367 ratios.freq_diff_reduced << 24);
Angel Pons7a87c922021-01-15 22:50:41 +0100368 break;
369 }
370}
371
372static void set_2dxx_series(struct raminfo *info, int s3resume)
373{
374 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
375 0, 1);
376 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
377 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
378 1);
379 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
380 frequency_11(info), 1231, 1524, 0, 1);
381 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
382 frequency_11(info) / 2, 1278, 2008, 0, 1);
383 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
384 1167, 1539, 0, 1);
385 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
386 frequency_11(info) / 2, 1403, 1318, 0, 1);
387 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
388 1);
389 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
390 1);
391 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
392 1, 1);
393 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
394 1);
395 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
396 frequency_11(info) / 2, 4000, 0, 0, 0);
397 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
398 frequency_11(info) / 2, 4000, 4000, 0, 0);
399
400 if (s3resume) {
401 printk(RAM_SPEW, "[6dc] <= %x\n",
402 info->cached_training->reg_6dc);
Angel Ponsdea722b2021-03-26 14:11:12 +0100403 mchbar_write32(0x6dc, info->cached_training->reg_6dc);
Angel Pons7a87c922021-01-15 22:50:41 +0100404 } else
405 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
406 info->delay46_ps[0], 0,
407 info->delay54_ps[0]);
408 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
409 frequency_11(info), 2500, 0, 0, 0);
410 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
411 frequency_11(info) / 2, 3500, 0, 0, 0);
412 if (s3resume) {
413 printk(RAM_SPEW, "[6e8] <= %x\n",
414 info->cached_training->reg_6e8);
Angel Ponsdea722b2021-03-26 14:11:12 +0100415 mchbar_write32(0x6e8, info->cached_training->reg_6e8);
Angel Pons7a87c922021-01-15 22:50:41 +0100416 } else
417 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
418 info->delay46_ps[1], 0,
419 info->delay54_ps[1]);
420 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
421 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
422 470, 0);
423 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
424 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
425 454, 459, 0);
426 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
427 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
428 2588, 0);
429 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
430 2405, 0);
431 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
432 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
433 480, 0);
434 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Angel Ponsdea722b2021-03-26 14:11:12 +0100435 mchbar_write32(0x2dbc, ((frequency_11(info) / 2) - 1) | 0xe00000);
436 mchbar_write32(0x2db8, (info->fsb_frequency - 1) << 16 | 0x77);
Angel Pons7a87c922021-01-15 22:50:41 +0100437}
438
Angel Pons56823f52021-01-16 11:27:33 +0100439static u16 quickpath_configure_pll_ratio(struct raminfo *info, const u8 x2ca8)
Angel Ponsa8b82712021-01-15 23:39:02 +0100440{
Angel Ponsdea722b2021-03-26 14:11:12 +0100441 mchbar_setbits32(0x18b4, 1 << 21 | 1 << 16);
442 mchbar_setbits32(0x1890, 1 << 25);
443 mchbar_setbits32(0x18b4, 1 << 15);
Angel Ponsa8b82712021-01-15 23:39:02 +0100444
Angel Pons56823f52021-01-16 11:27:33 +0100445 /* Get maximum supported PLL ratio */
446 u16 qpi_pll_ratio = (pci_read_config32(QPI_PHY_0, QPI_PLL_STATUS) >> 24 & 0x7f);
Angel Ponsa8b82712021-01-15 23:39:02 +0100447
Angel Pons56823f52021-01-16 11:27:33 +0100448 /* Adjust value if invalid */
449 if (qpi_pll_ratio == 0 || qpi_pll_ratio > 40)
450 qpi_pll_ratio = 40;
451
452 if (qpi_pll_ratio == 16)
453 qpi_pll_ratio = 12;
454
455 while (qpi_pll_ratio >= 12) {
456 if (qpi_pll_ratio <= (info->clock_speed_index + 3) * 8)
457 break;
458
459 qpi_pll_ratio -= 2;
460 }
461
462 /* Finally, program the ratio */
463 pci_write_config8(QPI_PHY_0, QPI_PLL_RATIO, qpi_pll_ratio);
464
Angel Ponsdea722b2021-03-26 14:11:12 +0100465 const u16 csipll0 = mchbar_read16(0x2c10);
466 mchbar_write16(0x2c10, (qpi_pll_ratio > 26) << 11 | 1 << 10 | qpi_pll_ratio);
Angel Pons56823f52021-01-16 11:27:33 +0100467
Angel Ponsdea722b2021-03-26 14:11:12 +0100468 if (csipll0 != mchbar_read16(0x2c10) && x2ca8 == 0)
469 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Pons56823f52021-01-16 11:27:33 +0100470
Angel Ponsdea722b2021-03-26 14:11:12 +0100471 mchbar_setbits16(0x2c12, 1 << 8);
Angel Ponsa8b82712021-01-15 23:39:02 +0100472
Angel Pons56823f52021-01-16 11:27:33 +0100473 return qpi_pll_ratio;
474}
475
476void early_quickpath_init(struct raminfo *info, const u8 x2ca8)
477{
478 u8 reg8;
479 u32 reg32;
480
481 /* Initialize DDR MPLL first */
482 if (x2ca8 == 0) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100483 mchbar_clrsetbits8(0x164, 0x26, info->clock_speed_index == 0 ? 0x24 : 0x26);
Angel Pons56823f52021-01-16 11:27:33 +0100484
485 /* Program DDR MPLL feedback divider ratio */
Angel Ponsdea722b2021-03-26 14:11:12 +0100486 mchbar_write16(0x2c20, (info->clock_speed_index + 3) * 4);
Angel Pons56823f52021-01-16 11:27:33 +0100487 }
488
489 const u16 qpi_pll_ratio = quickpath_configure_pll_ratio(info, x2ca8);
490
Angel Ponsdea722b2021-03-26 14:11:12 +0100491 mchbar_clrsetbits32(0x1804, 0x3, 0x8400080);
Angel Pons56823f52021-01-16 11:27:33 +0100492 pci_update_config32(QPI_PHY_0, QPI_PHY_CONTROL, 0xfffffffc, 0x400080);
Angel Ponsa8b82712021-01-15 23:39:02 +0100493
Angel Ponsdea722b2021-03-26 14:11:12 +0100494 const u32 x1c04 = mchbar_read32(0x1c04) & 0xc01080;
495 const u32 x1804 = mchbar_read32(0x1804) & 0xc01080;
Angel Ponsa8b82712021-01-15 23:39:02 +0100496
Angel Pons56823f52021-01-16 11:27:33 +0100497 if (x1c04 != x1804 && x2ca8 == 0)
Angel Ponsdea722b2021-03-26 14:11:12 +0100498 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Ponsa8b82712021-01-15 23:39:02 +0100499
Angel Ponsfa5ed052021-12-18 22:25:07 +0100500 reg32 = 0x3000000;
501 if (info->revision >= 0x18 && qpi_pll_ratio <= 12) {
502 /* Get TDP limit in 1/8W units */
503 const msr_t msr = rdmsr(MSR_TURBO_POWER_CURRENT_LIMIT);
504 if ((msr.lo & 0x7fff) <= 90)
505 reg32 = 0;
506 }
Angel Ponsdea722b2021-03-26 14:11:12 +0100507 mchbar_write32(0x18d8, 0x120000);
Angel Ponsfa5ed052021-12-18 22:25:07 +0100508 mchbar_write32(0x18dc, reg32 | 0xa484a);
509
510 reg32 = qpi_pll_ratio > 20 ? 8 : 16;
Angel Ponsa8b82712021-01-15 23:39:02 +0100511 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x0);
Angel Ponsfa5ed052021-12-18 22:25:07 +0100512 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x9404a | reg32 << 7);
513
Angel Ponsdea722b2021-03-26 14:11:12 +0100514 mchbar_write32(0x18d8, 0x40000);
515 mchbar_write32(0x18dc, 0xb000000);
Angel Ponsa8b82712021-01-15 23:39:02 +0100516 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x60000);
517 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x0);
Angel Ponsdea722b2021-03-26 14:11:12 +0100518 mchbar_write32(0x18d8, 0x180000);
519 mchbar_write32(0x18dc, 0xc0000142);
Angel Ponsa8b82712021-01-15 23:39:02 +0100520 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_SELECT, 0x20000);
521 pci_write_config32(QPI_PHY_0, QPI_PHY_EP_MCTR, 0x142);
Angel Ponsdea722b2021-03-26 14:11:12 +0100522 mchbar_write32(0x18d8, 0x1e0000);
Angel Ponsa8b82712021-01-15 23:39:02 +0100523
Angel Ponsdea722b2021-03-26 14:11:12 +0100524 const u32 x18dc = mchbar_read32(0x18dc);
525 mchbar_write32(0x18dc, qpi_pll_ratio < 18 ? 2 : 3);
Angel Ponsa8b82712021-01-15 23:39:02 +0100526
Angel Ponsdea722b2021-03-26 14:11:12 +0100527 if (x18dc != mchbar_read32(0x18dc) && x2ca8 == 0)
528 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Ponsa8b82712021-01-15 23:39:02 +0100529
Angel Pons56823f52021-01-16 11:27:33 +0100530 reg8 = qpi_pll_ratio > 20 ? 10 : 9;
531
Angel Ponsdea722b2021-03-26 14:11:12 +0100532 mchbar_write32(0x188c, 0x20bc00 | reg8);
Angel Pons56823f52021-01-16 11:27:33 +0100533 pci_write_config32(QPI_PHY_0, QPI_PHY_PWR_MGMT, 0x40b0c00 | reg8);
534
535 if (qpi_pll_ratio <= 14)
536 reg8 = 0x33;
Angel Ponsfa5ed052021-12-18 22:25:07 +0100537 else if (qpi_pll_ratio <= 22)
Angel Pons56823f52021-01-16 11:27:33 +0100538 reg8 = 0x42;
539 else
540 reg8 = 0x51;
541
Angel Ponsfa5ed052021-12-18 22:25:07 +0100542 info->fsb_frequency = qpi_pll_ratio * 15;
543 mchbar_write32(0x1a10, reg8 << 24 | info->fsb_frequency);
544
545 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
546 mchbar_setbits32(0x18b8, 0x200);
547 mchbar_setbits32(0x1918, 0x300);
548 }
Angel Ponsa8b82712021-01-15 23:39:02 +0100549
Angel Pons56823f52021-01-16 11:27:33 +0100550 if (info->revision > 0x17)
Angel Ponsdea722b2021-03-26 14:11:12 +0100551 mchbar_setbits32(0x18b8, 0xc00);
Angel Pons56823f52021-01-16 11:27:33 +0100552
553 reg32 = ((qpi_pll_ratio > 20) + 1) << 16;
554
Angel Ponsdea722b2021-03-26 14:11:12 +0100555 mchbar_clrsetbits32(0x182c, ~0xfff0f0ff, reg32 | 0x200);
Angel Pons56823f52021-01-16 11:27:33 +0100556 pci_update_config32(QPI_PHY_0, QPI_PHY_PRIM_TIMEOUT, 0xfff0f0ff, reg32 | 0x200);
Angel Ponsdea722b2021-03-26 14:11:12 +0100557 mchbar_clrbits32(0x1a1c, 7 << 28);
558 mchbar_setbits32(0x1a70, 1 << 20);
Angel Ponsa8b82712021-01-15 23:39:02 +0100559
Angel Ponsdea722b2021-03-26 14:11:12 +0100560 mchbar_clrbits32(0x18b4, 1 << 15);
561 mchbar_clrsetbits32(0x1a68, 0x00143fc0, 0x143800);
Angel Ponsa8b82712021-01-15 23:39:02 +0100562
Angel Ponsdea722b2021-03-26 14:11:12 +0100563 const u32 x1e68 = mchbar_read32(0x1e68) & 0x143fc0;
564 const u32 x1a68 = mchbar_read32(0x1a68) & 0x143fc0;
Angel Ponsa8b82712021-01-15 23:39:02 +0100565
Angel Pons56823f52021-01-16 11:27:33 +0100566 if (x1e68 != x1a68 && x2ca8 == 0)
Angel Ponsdea722b2021-03-26 14:11:12 +0100567 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Ponsa8b82712021-01-15 23:39:02 +0100568
Angel Pons56823f52021-01-16 11:27:33 +0100569 pci_update_config32(QPI_LINK_0, QPI_QPILCL, 0xffffff3f, 0x140000);
Angel Ponsa8b82712021-01-15 23:39:02 +0100570
Angel Pons56823f52021-01-16 11:27:33 +0100571 reg32 = pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS);
572 pci_write_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS, (reg32 & 0xfffe4555) | 0x64555);
573
574 if (reg32 != pci_read_config32(QPI_LINK_0, QPI_DEF_RMT_VN_CREDITS) && x2ca8 == 0)
Angel Ponsdea722b2021-03-26 14:11:12 +0100575 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Pons56823f52021-01-16 11:27:33 +0100576
577 pci_update_config32(QPI_NON_CORE, MIRROR_PORT_CTL, ~3, 0x80 * 3);
578
Angel Ponsdea722b2021-03-26 14:11:12 +0100579 reg32 = mchbar_read32(0x1af0);
580 mchbar_write32(0x1af0, (reg32 & 0xfdffcf) | 0x1f020000);
Angel Pons56823f52021-01-16 11:27:33 +0100581
Angel Ponsdea722b2021-03-26 14:11:12 +0100582 if (reg32 != mchbar_read32(0x1af0) && x2ca8 == 0)
583 mchbar_setbits8(0x2ca8, 1 << 0);
Angel Pons56823f52021-01-16 11:27:33 +0100584
Angel Ponsdea722b2021-03-26 14:11:12 +0100585 mchbar_clrbits32(0x1890, 1 << 25);
586 mchbar_clrsetbits32(0x18b4, 0xf << 12, 0x6 << 12);
587 mchbar_write32(0x18a4, 0x22222222);
588 mchbar_write32(0x18a8, 0x22222222);
589 mchbar_write32(0x18ac, 0x22222);
Angel Ponsa8b82712021-01-15 23:39:02 +0100590}
591
Angel Pons7a87c922021-01-15 22:50:41 +0100592void late_quickpath_init(struct raminfo *info, const int s3resume)
593{
594 const u16 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
595
Angel Pons7a87c922021-01-15 22:50:41 +0100596 if (s3resume && info->cached_training) {
Angel Pons0a8b1132021-01-15 23:13:00 +0100597 program_274265(info->cached_training);
Angel Pons7a87c922021-01-15 22:50:41 +0100598 } else {
Angel Pons0a8b1132021-01-15 23:13:00 +0100599 compute_274265(info);
600 program_274265(&info->training);
Angel Pons7a87c922021-01-15 22:50:41 +0100601 }
602
603 set_2dxx_series(info, s3resume);
604
605 if (!(deven & 8)) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100606 mchbar_clrsetbits32(0x2cb0, ~0, 0x40);
Angel Pons7a87c922021-01-15 22:50:41 +0100607 }
608
609 udelay(1000);
610
611 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100612 mchbar_setbits32(0xff8, 3 << 11);
613 mchbar_clrbits32(0x2cb0, ~0);
Angel Pons7a87c922021-01-15 22:50:41 +0100614 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
615 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
616 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
617
Angel Ponsdea722b2021-03-26 14:11:12 +0100618 mchbar_read8(0x1150);
619 mchbar_read8(0x1151);
620 mchbar_read8(0x1022);
621 mchbar_read8(0x16d0);
622 mchbar_write32(0x1300, 0x60606060);
623 mchbar_write32(0x1304, 0x60606060);
624 mchbar_write32(0x1308, 0x78797a7b);
625 mchbar_write32(0x130c, 0x7c7d7e7f);
626 mchbar_write32(0x1310, 0x60606060);
627 mchbar_write32(0x1314, 0x60606060);
628 mchbar_write32(0x1318, 0x60606060);
629 mchbar_write32(0x131c, 0x60606060);
630 mchbar_write32(0x1320, 0x50515253);
631 mchbar_write32(0x1324, 0x54555657);
632 mchbar_write32(0x1328, 0x58595a5b);
633 mchbar_write32(0x132c, 0x5c5d5e5f);
634 mchbar_write32(0x1330, 0x40414243);
635 mchbar_write32(0x1334, 0x44454647);
636 mchbar_write32(0x1338, 0x48494a4b);
637 mchbar_write32(0x133c, 0x4c4d4e4f);
638 mchbar_write32(0x1340, 0x30313233);
639 mchbar_write32(0x1344, 0x34353637);
640 mchbar_write32(0x1348, 0x38393a3b);
641 mchbar_write32(0x134c, 0x3c3d3e3f);
642 mchbar_write32(0x1350, 0x20212223);
643 mchbar_write32(0x1354, 0x24252627);
644 mchbar_write32(0x1358, 0x28292a2b);
645 mchbar_write32(0x135c, 0x2c2d2e2f);
646 mchbar_write32(0x1360, 0x10111213);
647 mchbar_write32(0x1364, 0x14151617);
648 mchbar_write32(0x1368, 0x18191a1b);
649 mchbar_write32(0x136c, 0x1c1d1e1f);
650 mchbar_write32(0x1370, 0x10203);
651 mchbar_write32(0x1374, 0x4050607);
652 mchbar_write32(0x1378, 0x8090a0b);
653 mchbar_write32(0x137c, 0xc0d0e0f);
654 mchbar_write8(0x11cc, 0x4e);
655 mchbar_write32(0x1110, 0x73970404);
656 mchbar_write32(0x1114, 0x72960404);
657 mchbar_write32(0x1118, 0x6f950404);
658 mchbar_write32(0x111c, 0x6d940404);
659 mchbar_write32(0x1120, 0x6a930404);
660 mchbar_write32(0x1124, 0x68a41404);
661 mchbar_write32(0x1128, 0x66a21404);
662 mchbar_write32(0x112c, 0x63a01404);
663 mchbar_write32(0x1130, 0x609e1404);
664 mchbar_write32(0x1134, 0x5f9c1404);
665 mchbar_write32(0x1138, 0x5c961404);
666 mchbar_write32(0x113c, 0x58a02404);
667 mchbar_write32(0x1140, 0x54942404);
668 mchbar_write32(0x1190, 0x900080a);
669 mchbar_write16(0x11c0, 0xc40b);
670 mchbar_write16(0x11c2, 0x303);
671 mchbar_write16(0x11c4, 0x301);
672 mchbar_clrsetbits32(0x1190, ~0, 0x8900080a);
673 mchbar_write32(0x11b8, 0x70c3000);
674 mchbar_write8(0x11ec, 0xa);
675 mchbar_write16(0x1100, 0x800);
676 mchbar_clrsetbits32(0x11bc, ~0, 0x1e84800);
677 mchbar_write16(0x11ca, 0xfa);
678 mchbar_write32(0x11e4, 0x4e20);
679 mchbar_write8(0x11bc, 0xf);
680 mchbar_write16(0x11da, 0x19);
681 mchbar_write16(0x11ba, 0x470c);
682 mchbar_write32(0x1680, 0xe6ffe4ff);
683 mchbar_write32(0x1684, 0xdeffdaff);
684 mchbar_write32(0x1688, 0xd4ffd0ff);
685 mchbar_write32(0x168c, 0xccffc6ff);
686 mchbar_write32(0x1690, 0xc0ffbeff);
687 mchbar_write32(0x1694, 0xb8ffb0ff);
688 mchbar_write32(0x1698, 0xa8ff0000);
689 mchbar_write32(0x169c, 0xc00);
690 mchbar_write32(0x1290, 0x5000000);
Angel Pons7a87c922021-01-15 22:50:41 +0100691 }
692
Angel Ponsdea722b2021-03-26 14:11:12 +0100693 mchbar_write32(0x124c, 0x15040d00);
694 mchbar_write32(0x1250, 0x7f0000);
695 mchbar_write32(0x1254, 0x1e220004);
696 mchbar_write32(0x1258, 0x4000004);
697 mchbar_write32(0x1278, 0x0);
698 mchbar_write32(0x125c, 0x0);
699 mchbar_write32(0x1260, 0x0);
700 mchbar_write32(0x1264, 0x0);
701 mchbar_write32(0x1268, 0x0);
702 mchbar_write32(0x126c, 0x0);
703 mchbar_write32(0x1270, 0x0);
704 mchbar_write32(0x1274, 0x0);
Angel Pons7a87c922021-01-15 22:50:41 +0100705
706 if (deven & 8) {
Angel Ponsdea722b2021-03-26 14:11:12 +0100707 mchbar_write16(0x1214, 0x320);
708 mchbar_write32(0x1600, 0x40000000);
709 mchbar_clrsetbits32(0x11f4, ~0, 1 << 28);
710 mchbar_clrsetbits16(0x1230, ~0, 1 << 15);
711 mchbar_write32(0x1400, 0x13040020);
712 mchbar_write32(0x1404, 0xe090120);
713 mchbar_write32(0x1408, 0x5120220);
714 mchbar_write32(0x140c, 0x5120330);
715 mchbar_write32(0x1410, 0xe090220);
716 mchbar_write32(0x1414, 0x1010001);
717 mchbar_write32(0x1418, 0x1110000);
718 mchbar_write32(0x141c, 0x9020020);
719 mchbar_write32(0x1420, 0xd090220);
720 mchbar_write32(0x1424, 0x2090220);
721 mchbar_write32(0x1428, 0x2090330);
722 mchbar_write32(0x142c, 0xd090220);
723 mchbar_write32(0x1430, 0x1010001);
724 mchbar_write32(0x1434, 0x1110000);
725 mchbar_write32(0x1438, 0x11040020);
726 mchbar_write32(0x143c, 0x4030220);
727 mchbar_write32(0x1440, 0x1060220);
728 mchbar_write32(0x1444, 0x1060330);
729 mchbar_write32(0x1448, 0x4030220);
730 mchbar_write32(0x144c, 0x1010001);
731 mchbar_write32(0x1450, 0x1110000);
732 mchbar_write32(0x1454, 0x4010020);
733 mchbar_write32(0x1458, 0xb090220);
734 mchbar_write32(0x145c, 0x1090220);
735 mchbar_write32(0x1460, 0x1090330);
736 mchbar_write32(0x1464, 0xb090220);
737 mchbar_write32(0x1468, 0x1010001);
738 mchbar_write32(0x146c, 0x1110000);
739 mchbar_write32(0x1470, 0xf040020);
740 mchbar_write32(0x1474, 0xa090220);
741 mchbar_write32(0x1478, 0x1120220);
742 mchbar_write32(0x147c, 0x1120330);
743 mchbar_write32(0x1480, 0xa090220);
744 mchbar_write32(0x1484, 0x1010001);
745 mchbar_write32(0x1488, 0x1110000);
746 mchbar_write32(0x148c, 0x7020020);
747 mchbar_write32(0x1490, 0x1010220);
748 mchbar_write32(0x1494, 0x10210);
749 mchbar_write32(0x1498, 0x10320);
750 mchbar_write32(0x149c, 0x1010220);
751 mchbar_write32(0x14a0, 0x1010001);
752 mchbar_write32(0x14a4, 0x1110000);
753 mchbar_write32(0x14a8, 0xd040020);
754 mchbar_write32(0x14ac, 0x8090220);
755 mchbar_write32(0x14b0, 0x1111310);
756 mchbar_write32(0x14b4, 0x1111420);
757 mchbar_write32(0x14b8, 0x8090220);
758 mchbar_write32(0x14bc, 0x1010001);
759 mchbar_write32(0x14c0, 0x1110000);
760 mchbar_write32(0x14c4, 0x3010020);
761 mchbar_write32(0x14c8, 0x7090220);
762 mchbar_write32(0x14cc, 0x1081310);
763 mchbar_write32(0x14d0, 0x1081420);
764 mchbar_write32(0x14d4, 0x7090220);
765 mchbar_write32(0x14d8, 0x1010001);
766 mchbar_write32(0x14dc, 0x1110000);
767 mchbar_write32(0x14e0, 0xb040020);
768 mchbar_write32(0x14e4, 0x2030220);
769 mchbar_write32(0x14e8, 0x1051310);
770 mchbar_write32(0x14ec, 0x1051420);
771 mchbar_write32(0x14f0, 0x2030220);
772 mchbar_write32(0x14f4, 0x1010001);
773 mchbar_write32(0x14f8, 0x1110000);
774 mchbar_write32(0x14fc, 0x5020020);
775 mchbar_write32(0x1500, 0x5090220);
776 mchbar_write32(0x1504, 0x2071310);
777 mchbar_write32(0x1508, 0x2071420);
778 mchbar_write32(0x150c, 0x5090220);
779 mchbar_write32(0x1510, 0x1010001);
780 mchbar_write32(0x1514, 0x1110000);
781 mchbar_write32(0x1518, 0x7040120);
782 mchbar_write32(0x151c, 0x2090220);
783 mchbar_write32(0x1520, 0x70b1210);
784 mchbar_write32(0x1524, 0x70b1310);
785 mchbar_write32(0x1528, 0x2090220);
786 mchbar_write32(0x152c, 0x1010001);
787 mchbar_write32(0x1530, 0x1110000);
788 mchbar_write32(0x1534, 0x1010110);
789 mchbar_write32(0x1538, 0x1081310);
790 mchbar_write32(0x153c, 0x5041200);
791 mchbar_write32(0x1540, 0x5041310);
792 mchbar_write32(0x1544, 0x1081310);
793 mchbar_write32(0x1548, 0x1010001);
794 mchbar_write32(0x154c, 0x1110000);
795 mchbar_write32(0x1550, 0x1040120);
796 mchbar_write32(0x1554, 0x4051210);
797 mchbar_write32(0x1558, 0xd051200);
798 mchbar_write32(0x155c, 0xd051200);
799 mchbar_write32(0x1560, 0x4051210);
800 mchbar_write32(0x1564, 0x1010001);
801 mchbar_write32(0x1568, 0x1110000);
802 mchbar_write16(0x1222, 0x220a);
803 mchbar_write16(0x123c, 0x1fc0);
804 mchbar_write16(0x1220, 0x1388);
Angel Pons7a87c922021-01-15 22:50:41 +0100805 }
806}