blob: a992d9c98cb971d752a7e2085119186cfafe5c40 [file] [log] [blame]
Patrick Rudolph305035c2016-11-11 18:38:50 +01001/*
2 * This file is part of the coreboot project.
3 *
Patrick Rudolph305035c2016-11-11 18:38:50 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <console/console.h>
16#include <console/usb.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010017#include <delay.h>
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +010018#include <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010019#include "raminit_native.h"
20#include "raminit_common.h"
21
22/* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010023static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010024{
25 u32 FRQ;
Patrick Rudolph77eaba32016-11-11 18:55:54 +010026
27 FRQ = 256000 / (tCK * base_freq);
28
29 if (base_freq == 100) {
30 if (FRQ > 12)
31 return 12;
32 if (FRQ < 7)
33 return 7;
34 } else {
35 if (FRQ > 10)
36 return 10;
37 if (FRQ < 3)
38 return 3;
39 }
40
Patrick Rudolph305035c2016-11-11 18:38:50 +010041 return FRQ;
42}
43
Patrick Rudolph77eaba32016-11-11 18:55:54 +010044static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010045{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010046 u32 refi;
47
48 if (base_freq == 100) {
49 /* Get REFI based on MCU frequency using the following rule:
50 * tREFI = 7.8usec
51 * _________________________________________
52 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
53 * REFI : | 5460 | 6240 | 7020 | 7800 | 8580 | 9360 |
54 */
55 static const u32 frq_xs_map[] =
56 { 5460, 6240, 7020, 7800, 8580, 9360 };
57 refi = frq_xs_map[get_FRQ(tCK, 100) - 7];
58 } else {
59 /* Get REFI based on MCU frequency using the following rule:
60 * tREFI = 7.8usec
61 * ________________________________________________________
62 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
63 * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | 9360 | 10400 |
64 */
65 static const u32 frq_refi_map[] =
66 { 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400 };
67 refi = frq_refi_map[get_FRQ(tCK, 133) - 3];
68 }
69
70 return refi;
Patrick Rudolph305035c2016-11-11 18:38:50 +010071}
72
Patrick Rudolph77eaba32016-11-11 18:55:54 +010073static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010074{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010075 u8 xsoffset;
76
77 if (base_freq == 100) {
78 /* Get XSOffset based on MCU frequency using the following rule:
79 * tXS-offset: tXS = tRFC+10ns.
80 * _____________________________
81 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
82 * XSOffset : | 7 | 8 | 9 | 10 | 11 | 12 |
83 */
84 static const u8 frq_xs_map[] = { 7, 8, 9, 10, 11, 12 };
85 xsoffset = frq_xs_map[get_FRQ(tCK, 100) - 7];
86 } else {
87 /* Get XSOffset based on MCU frequency using the following rule:
88 * ___________________________________
89 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
90 * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 14 |
91 */
92 static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11, 12, 14 };
93 xsoffset = frq_xs_map[get_FRQ(tCK, 133) - 3];
94 }
95
96 return xsoffset;
Patrick Rudolph305035c2016-11-11 18:38:50 +010097}
98
Patrick Rudolph77eaba32016-11-11 18:55:54 +010099static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100100{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100101 u8 mod;
102
103 if (base_freq == 100) {
104 /* Get MOD based on MCU frequency using the following rule:
105 * _____________________________
106 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
107 * MOD : | 12 | 12 | 14 | 15 | 17 | 18 |
108 */
109
110 static const u8 frq_mod_map[] = { 12, 12, 14, 15, 17, 18 };
111 mod = frq_mod_map[get_FRQ(tCK, 100) - 7];
112 } else {
113 /* Get MOD based on MCU frequency using the following rule:
114 * _______________________________________
115 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
116 * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | 18 | 20 |
117 */
118
119 static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16, 18, 20 };
120 mod = frq_mod_map[get_FRQ(tCK, 133) - 3];
121 }
122 return mod;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100123}
124
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100125static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100126{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100127 u8 wlo;
128
129 if (base_freq == 100) {
130 /* Get WLO based on MCU frequency using the following rule:
131 * Write leveling output delay
132 * _____________________________
133 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
134 * MOD : | 6 | 6 | 7 | 8 | 9 | 9 |
135 */
136
137 static const u8 frq_wlo_map[] = { 6, 6, 7, 8, 9, 9 };
138 wlo = frq_wlo_map[get_FRQ(tCK, 100) - 7];
139 } else {
140 /* Get WLO based on MCU frequency using the following rule:
141 * Write leveling output delay
142 * ________________________________
143 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
144 * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | 9 | 10 |
145 */
146 static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8, 9, 10 };
147 wlo = frq_wlo_map[get_FRQ(tCK, 133) - 3];
148 }
149
150 return wlo;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100151}
152
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100153static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100154{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100155 u8 cke;
156
157 if (base_freq == 100) {
158 /* Get CKE based on MCU frequency using the following rule:
159 * _____________________________
160 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
161 * MOD : | 4 | 4 | 5 | 5 | 6 | 6 |
162 */
163
164 static const u8 frq_cke_map[] = { 4, 4, 5, 5, 6, 6 };
165 cke = frq_cke_map[get_FRQ(tCK, 100) - 7];
166 } else {
167 /* Get CKE based on MCU frequency using the following rule:
168 * ________________________________
169 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
170 * WLO : | 3 | 3 | 4 | 4 | 5 | 6 | 6 | 7 |
171 */
172 static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6, 6, 7 };
173 cke = frq_cke_map[get_FRQ(tCK, 133) - 3];
174 }
175
176 return cke;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100177}
178
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100179static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100180{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100181 u8 xpdll;
182
183 if (base_freq == 100) {
184 /* Get XPDLL based on MCU frequency using the following rule:
185 * _____________________________
186 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
187 * XPDLL : | 17 | 20 | 22 | 24 | 27 | 32 |
188 */
189
190 static const u8 frq_xpdll_map[] = { 17, 20, 22, 24, 27, 32 };
191 xpdll = frq_xpdll_map[get_FRQ(tCK, 100) - 7];
192 } else {
193 /* Get XPDLL based on MCU frequency using the following rule:
194 * _______________________________________
195 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
196 * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | 29 | 32 |
197 */
198 static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26, 29, 32 };
199 xpdll = frq_xpdll_map[get_FRQ(tCK, 133) - 3];
200 }
201
202 return xpdll;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100203}
204
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100205static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100206{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100207 u8 xp;
208
209 if (base_freq == 100) {
210 /* Get XP based on MCU frequency using the following rule:
211 * _____________________________
212 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
213 * XP : | 5 | 5 | 6 | 6 | 7 | 8 |
214 */
215
216 static const u8 frq_xp_map[] = { 5, 5, 6, 6, 7, 8 };
217 xp = frq_xp_map[get_FRQ(tCK, 100) - 7];
218 } else {
219 /* Get XP based on MCU frequency using the following rule:
220 * _______________________________________
221 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
222 * XP : | 3 | 4 | 4 | 5 | 6 | 7 | 8 | 8 |
223 */
Elyes HAOUASa342f392018-10-17 10:56:26 +0200224 static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7, 8, 8 };
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100225 xp = frq_xp_map[get_FRQ(tCK, 133) - 3];
226 }
227
228 return xp;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100229}
230
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100231static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100232{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100233 u8 aonpd;
234
235 if (base_freq == 100) {
236 /* Get AONPD based on MCU frequency using the following rule:
237 * _____________________________
238 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
239 * AONPD : | 6 | 8 | 8 | 9 | 10 | 11 |
240 */
241
242 static const u8 frq_aonpd_map[] = { 6, 8, 8, 9, 10, 11 };
243 aonpd = frq_aonpd_map[get_FRQ(tCK, 100) - 7];
244 } else {
245 /* Get AONPD based on MCU frequency using the following rule:
246 * _______________________________________
247 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
248 * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | 11 | 12 |
249 */
250 static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10, 11, 12 };
251 aonpd = frq_aonpd_map[get_FRQ(tCK, 133) - 3];
252 }
253
254 return aonpd;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100255}
256
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100257static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100258{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100259 u32 comp2;
260
261 if (base_freq == 100) {
262 /* Get COMP2 based on MCU frequency using the following rule:
263 * ______________________________________________________________
264 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
265 * COMP : | CA8C264 | C6671E4 | C6671E4 | C446964 | C235924 | C235924 |
266 */
267
268 static const u32 frq_comp2_map[] = { 0xCA8C264, 0xC6671E4, 0xC6671E4, 0xC446964, 0xC235924, 0xC235924 };
269 comp2 = frq_comp2_map[get_FRQ(tCK, 100) - 7];
270 } else {
271 /* Get COMP2 based on MCU frequency using the following rule:
272 * ________________________________________________________________________________
273 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
274 * COMP : | D6FF5E4 | CEBDB64 | CA8C264 | C6671E4 | C446964 | C235924 | C235924 | C235924 |
275 */
276 static const u32 frq_comp2_map[] = { 0xD6FF5E4, 0xCEBDB64, 0xCA8C264,
277 0xC6671E4, 0xC446964, 0xC235924, 0xC235924, 0xC235924
278 };
279 comp2 = frq_comp2_map[get_FRQ(tCK, 133) - 3];
280 }
281
282 return comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100283}
284
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200285static void ivb_normalize_tclk(ramctr_timing *ctrl,
286 bool ref_100mhz_support)
287{
288 if (ctrl->tCK <= TCK_1200MHZ) {
289 ctrl->tCK = TCK_1200MHZ;
290 ctrl->base_freq = 100;
291 } else if (ctrl->tCK <= TCK_1100MHZ) {
292 ctrl->tCK = TCK_1100MHZ;
293 ctrl->base_freq = 100;
294 } else if (ctrl->tCK <= TCK_1066MHZ) {
295 ctrl->tCK = TCK_1066MHZ;
296 ctrl->base_freq = 133;
297 } else if (ctrl->tCK <= TCK_1000MHZ) {
298 ctrl->tCK = TCK_1000MHZ;
299 ctrl->base_freq = 100;
300 } else if (ctrl->tCK <= TCK_933MHZ) {
301 ctrl->tCK = TCK_933MHZ;
302 ctrl->base_freq = 133;
303 } else if (ctrl->tCK <= TCK_900MHZ) {
304 ctrl->tCK = TCK_900MHZ;
305 ctrl->base_freq = 100;
306 } else if (ctrl->tCK <= TCK_800MHZ) {
307 ctrl->tCK = TCK_800MHZ;
308 ctrl->base_freq = 133;
309 } else if (ctrl->tCK <= TCK_700MHZ) {
310 ctrl->tCK = TCK_700MHZ;
311 ctrl->base_freq = 100;
312 } else if (ctrl->tCK <= TCK_666MHZ) {
313 ctrl->tCK = TCK_666MHZ;
314 ctrl->base_freq = 133;
315 } else if (ctrl->tCK <= TCK_533MHZ) {
316 ctrl->tCK = TCK_533MHZ;
317 ctrl->base_freq = 133;
318 } else if (ctrl->tCK <= TCK_400MHZ) {
319 ctrl->tCK = TCK_400MHZ;
320 ctrl->base_freq = 133;
321 } else {
322 ctrl->tCK = 0;
323 return;
324 }
325
326 if (!ref_100mhz_support && ctrl->base_freq == 100) {
327 /* Skip unsupported frequency. */
328 ctrl->tCK++;
329 ivb_normalize_tclk(ctrl, ref_100mhz_support);
330 }
331}
332
333static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100334{
335 u8 val;
336 u32 val32;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200337 u32 reg32;
338 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100339
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200340 /* 100 Mhz reference clock supported */
341 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
342 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
343 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n",
344 ref_100mhz_support ? "yes" : "no");
345
346 /* Find CAS latency */
347 while (1) {
348 /* Normalising tCK before computing clock could potentially
349 * results in lower selected CAS, which is desired.
350 */
351 ivb_normalize_tclk(ctrl, ref_100mhz_support);
352 if (!(ctrl->tCK))
353 die("Couldn't find compatible clock / CAS settings\n");
354 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
355 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
356 for (; val <= MAX_CAS; val++)
357 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
358 break;
359 if (val == (MAX_CAS + 1)) {
360 ctrl->tCK++;
361 continue;
362 } else {
363 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
364 break;
365 }
366 }
367
368 val32 = NS2MHZ_DIV256 / ctrl->tCK;
369 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
370
371 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
372 ctrl->CAS = val;
373}
374
375
376static void dram_timing(ramctr_timing *ctrl)
377{
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100378 /* Maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
379 * We cap it at 1200Mhz (DDR3 2400).
Patrick Rudolph305035c2016-11-11 18:38:50 +0100380 * Then, align it to the closest JEDEC standard frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200381 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100382 ctrl->edge_offset[0] = 18; //XXX: guessed
383 ctrl->edge_offset[1] = 8;
384 ctrl->edge_offset[2] = 8;
385 ctrl->timC_offset[0] = 20; //XXX: guessed
386 ctrl->timC_offset[1] = 8;
387 ctrl->timC_offset[2] = 8;
Angel Pons88521882020-01-05 20:21:20 +0100388 ctrl->pi_coding_threshold = 10;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200389 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100390 ctrl->edge_offset[0] = 17; //XXX: guessed
391 ctrl->edge_offset[1] = 7;
392 ctrl->edge_offset[2] = 7;
393 ctrl->timC_offset[0] = 19; //XXX: guessed
394 ctrl->timC_offset[1] = 7;
395 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100396 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200397 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100398 ctrl->edge_offset[0] = 16;
399 ctrl->edge_offset[1] = 7;
400 ctrl->edge_offset[2] = 7;
401 ctrl->timC_offset[0] = 18;
402 ctrl->timC_offset[1] = 7;
403 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100404 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200405 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100406 ctrl->edge_offset[0] = 15; //XXX: guessed
407 ctrl->edge_offset[1] = 6;
408 ctrl->edge_offset[2] = 6;
409 ctrl->timC_offset[0] = 17; //XXX: guessed
410 ctrl->timC_offset[1] = 6;
411 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100412 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200413 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100414 ctrl->edge_offset[0] = 14;
415 ctrl->edge_offset[1] = 6;
416 ctrl->edge_offset[2] = 6;
417 ctrl->timC_offset[0] = 15;
418 ctrl->timC_offset[1] = 6;
419 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100420 ctrl->pi_coding_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200421 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100422 ctrl->edge_offset[0] = 14; //XXX: guessed
423 ctrl->edge_offset[1] = 6;
424 ctrl->edge_offset[2] = 6;
425 ctrl->timC_offset[0] = 15; //XXX: guessed
426 ctrl->timC_offset[1] = 6;
427 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100428 ctrl->pi_coding_threshold = 12;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200429 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100430 ctrl->edge_offset[0] = 13;
431 ctrl->edge_offset[1] = 5;
432 ctrl->edge_offset[2] = 5;
433 ctrl->timC_offset[0] = 14;
434 ctrl->timC_offset[1] = 5;
435 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100436 ctrl->pi_coding_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200437 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100438 ctrl->edge_offset[0] = 13; //XXX: guessed
439 ctrl->edge_offset[1] = 5;
440 ctrl->edge_offset[2] = 5;
441 ctrl->timC_offset[0] = 14; //XXX: guessed
442 ctrl->timC_offset[1] = 5;
443 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100444 ctrl->pi_coding_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200445 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100446 ctrl->edge_offset[0] = 10;
447 ctrl->edge_offset[1] = 4;
448 ctrl->edge_offset[2] = 4;
449 ctrl->timC_offset[0] = 11;
450 ctrl->timC_offset[1] = 4;
451 ctrl->timC_offset[2] = 4;
Angel Pons88521882020-01-05 20:21:20 +0100452 ctrl->pi_coding_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200453 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100454 ctrl->edge_offset[0] = 8;
455 ctrl->edge_offset[1] = 3;
456 ctrl->edge_offset[2] = 3;
457 ctrl->timC_offset[0] = 9;
458 ctrl->timC_offset[1] = 3;
459 ctrl->timC_offset[2] = 3;
Angel Pons88521882020-01-05 20:21:20 +0100460 ctrl->pi_coding_threshold = 17;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200461 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100462 ctrl->edge_offset[0] = 6;
463 ctrl->edge_offset[1] = 2;
464 ctrl->edge_offset[2] = 2;
465 ctrl->timC_offset[0] = 6;
466 ctrl->timC_offset[1] = 2;
467 ctrl->timC_offset[2] = 2;
Angel Pons88521882020-01-05 20:21:20 +0100468 ctrl->pi_coding_threshold = 17;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100469 }
470
471 /* Initial phase between CLK/CMD pins */
Angel Pons88521882020-01-05 20:21:20 +0100472 ctrl->pi_code_offset = (256000 / ctrl->tCK) / 66;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100473
474 /* DLL_CONFIG_MDLL_W_TIMER */
Angel Pons88521882020-01-05 20:21:20 +0100475 ctrl->mdll_wake_delay = (128000 / ctrl->tCK) + 3;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100476
Dan Elkoubydabebc32018-04-13 18:47:10 +0300477 if (ctrl->tCWL)
478 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
479 else
480 ctrl->CWL = get_CWL(ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100481 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
482
483 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100484 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100485 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
486
Arthur Heymans50db9c92017-03-23 18:53:38 +0100487 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100488 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
489
490 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100491 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100492 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
493
494 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100495 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100496 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
497
498 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100499 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100500 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
501
502 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100503 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100504 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
505
506 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100507 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100508 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
509
510 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100511 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100512 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
513
514 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100515 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100516 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
517
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100518 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
519 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
520 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
521 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
522 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
523 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
524 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
525 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100526}
527
Angel Pons88521882020-01-05 20:21:20 +0100528static void dram_freq(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100529{
530 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100531 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
532 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100533 ctrl->tCK = TCK_400MHZ;
534 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100535
Patrick Rudolph305035c2016-11-11 18:38:50 +0100536 while (1) {
537 u8 val2;
538 u32 reg1 = 0;
539
540 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200541 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100542
Patrick Rudolph305035c2016-11-11 18:38:50 +0100543 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100544 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100545
546 /* The PLL will never lock if the required frequency is
547 * already set. Exit early to prevent a system hang.
548 */
549 reg1 = MCHBAR32(MC_BIOS_DATA);
550 val2 = (u8) reg1;
551 if (val2)
552 return;
553
554 /* Step 2 - Select frequency in the MCU */
555 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100556 if (ctrl->base_freq == 100)
557 reg1 |= 0x100; /* Enable 100Mhz REF clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100558 reg1 |= 0x80000000; // set running bit
559 MCHBAR32(MC_BIOS_REQ) = reg1;
560 int i=0;
561 printk(BIOS_DEBUG, "PLL busy... ");
562 while (reg1 & 0x80000000) {
563 udelay(10);
564 i++;
565 reg1 = MCHBAR32(MC_BIOS_REQ);
566 }
567 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
568
569 /* Step 3 - Verify lock frequency */
570 reg1 = MCHBAR32(MC_BIOS_DATA);
571 val2 = (u8) reg1;
572 if (val2 >= FRQ) {
573 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
574 (1000 << 8) / ctrl->tCK);
575 return;
576 }
577 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
578 ctrl->tCK++;
579 }
580}
581
Angel Pons88521882020-01-05 20:21:20 +0100582static void dram_ioregs(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100583{
584 u32 reg, comp2;
585
586 int channel;
587
588 // IO clock
589 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100590 MCHBAR32(GDCRCLKRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100591 }
592
593 // IO command
594 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100595 MCHBAR32(GDCRCTLRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100596 }
597
598 // IO control
599 FOR_ALL_POPULATED_CHANNELS {
600 program_timings(ctrl, channel);
601 }
602
603 // Rcomp
604 printram("RCOMP...");
605 reg = 0;
606 while (reg == 0) {
Angel Pons88521882020-01-05 20:21:20 +0100607 reg = MCHBAR32(RCOMP_TIMER) & 0x10000;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100608 }
609 printram("done\n");
610
611 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100612 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Angel Pons88521882020-01-05 20:21:20 +0100613 MCHBAR32(CRCOMPOFST2) = comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100614 printram("COMP2 done\n");
615
616 // Set comp1
617 FOR_ALL_POPULATED_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100618 reg = MCHBAR32(CRCOMPOFST1_ch(channel)); //ch0
Patrick Rudolph305035c2016-11-11 18:38:50 +0100619 reg = (reg & ~0xe00) | (1 << 9); //odt
620 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
621 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
Angel Pons88521882020-01-05 20:21:20 +0100622 MCHBAR32(CRCOMPOFST1_ch(channel)) = reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100623 }
624 printram("COMP1 done\n");
625
626 printram("FORCE RCOMP and wait 20us...");
Angel Pons88521882020-01-05 20:21:20 +0100627 MCHBAR32(M_COMP) |= 0x100;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100628 udelay(20);
629 printram("done\n");
630}
631
632int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
633 int s3_resume, int me_uma_size)
634{
635 int err;
636
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100637 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
638 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100639
640 if (!fast_boot) {
641 /* Find fastest common supported parameters */
642 dram_find_common_params(ctrl);
643
644 dram_dimm_mapping(ctrl);
645 }
646
647 /* Set MCU frequency */
648 dram_freq(ctrl);
649
650 if (!fast_boot) {
651 /* Calculate timings */
652 dram_timing(ctrl);
653 }
654
655 /* Set version register */
Angel Pons88521882020-01-05 20:21:20 +0100656 MCHBAR32(MRC_REVISION) = 0xC04EB002;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100657
658 /* Enable crossover */
659 dram_xover(ctrl);
660
661 /* Set timing and refresh registers */
662 dram_timing_regs(ctrl);
663
664 /* Power mode preset */
Angel Pons88521882020-01-05 20:21:20 +0100665 MCHBAR32(PM_THML_STAT) = 0x5500;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100666
Angel Pons88521882020-01-05 20:21:20 +0100667 /* Set scheduler chicken bits */
668 MCHBAR32(SCHED_CBIT) = 0x10100005;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100669
670 /* Set CPU specific register */
671 set_4f8c();
672
673 /* Clear IO reset bit */
Angel Pons88521882020-01-05 20:21:20 +0100674 MCHBAR32(MC_INIT_STATE_G) &= ~0x20;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100675
676 /* Set MAD-DIMM registers */
677 dram_dimm_set_mapping(ctrl);
678 printk(BIOS_DEBUG, "Done dimm mapping\n");
679
680 /* Zone config */
681 dram_zones(ctrl, 1);
682
683 /* Set memory map */
684 dram_memorymap(ctrl, me_uma_size);
685 printk(BIOS_DEBUG, "Done memory map\n");
686
687 /* Set IO registers */
688 dram_ioregs(ctrl);
689 printk(BIOS_DEBUG, "Done io registers\n");
690
691 udelay(1);
692
693 if (fast_boot) {
694 restore_timings(ctrl);
695 } else {
696 /* Do jedec ddr3 reset sequence */
697 dram_jedecreset(ctrl);
698 printk(BIOS_DEBUG, "Done jedec reset\n");
699
700 /* MRS commands */
701 dram_mrscommands(ctrl);
702 printk(BIOS_DEBUG, "Done MRS commands\n");
703
704 /* Prepare for memory training */
705 prepare_training(ctrl);
706
707 err = read_training(ctrl);
708 if (err)
709 return err;
710
711 err = write_training(ctrl);
712 if (err)
713 return err;
714
715 printram("CP5a\n");
716
717 err = discover_edges(ctrl);
718 if (err)
719 return err;
720
721 printram("CP5b\n");
722
723 err = command_training(ctrl);
724 if (err)
725 return err;
726
727 printram("CP5c\n");
728
729 err = discover_edges_write(ctrl);
730 if (err)
731 return err;
732
733 err = discover_timC_write(ctrl);
734 if (err)
735 return err;
736
737 normalize_training(ctrl);
738 }
739
740 set_4008c(ctrl);
741
742 write_controller_mr(ctrl);
743
744 if (!s3_resume) {
745 err = channel_test(ctrl);
746 if (err)
747 return err;
748 }
749
750 return 0;
751}