blob: 20f30389d89af6817a8e97e8131d99adeb05ec3a [file] [log] [blame]
Patrick Rudolph305035c2016-11-11 18:38:50 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
5 * Copyright (C) 2014 Vladimir Serbinenko <phcoder@gmail.com>
6 * Copyright (C) 2016 Patrick Rudolph <siro@das-labor.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <console/console.h>
19#include <console/usb.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010020#include <delay.h>
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +010021#include <arch/io.h>
22#include <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010023#include "raminit_native.h"
24#include "raminit_common.h"
25
26/* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010027static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010028{
29 u32 FRQ;
Patrick Rudolph77eaba32016-11-11 18:55:54 +010030
31 FRQ = 256000 / (tCK * base_freq);
32
33 if (base_freq == 100) {
34 if (FRQ > 12)
35 return 12;
36 if (FRQ < 7)
37 return 7;
38 } else {
39 if (FRQ > 10)
40 return 10;
41 if (FRQ < 3)
42 return 3;
43 }
44
Patrick Rudolph305035c2016-11-11 18:38:50 +010045 return FRQ;
46}
47
Patrick Rudolph77eaba32016-11-11 18:55:54 +010048static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010049{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010050 u32 refi;
51
52 if (base_freq == 100) {
53 /* Get REFI based on MCU frequency using the following rule:
54 * tREFI = 7.8usec
55 * _________________________________________
56 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
57 * REFI : | 5460 | 6240 | 7020 | 7800 | 8580 | 9360 |
58 */
59 static const u32 frq_xs_map[] =
60 { 5460, 6240, 7020, 7800, 8580, 9360 };
61 refi = frq_xs_map[get_FRQ(tCK, 100) - 7];
62 } else {
63 /* Get REFI based on MCU frequency using the following rule:
64 * tREFI = 7.8usec
65 * ________________________________________________________
66 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
67 * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | 9360 | 10400 |
68 */
69 static const u32 frq_refi_map[] =
70 { 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400 };
71 refi = frq_refi_map[get_FRQ(tCK, 133) - 3];
72 }
73
74 return refi;
Patrick Rudolph305035c2016-11-11 18:38:50 +010075}
76
Patrick Rudolph77eaba32016-11-11 18:55:54 +010077static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010078{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010079 u8 xsoffset;
80
81 if (base_freq == 100) {
82 /* Get XSOffset based on MCU frequency using the following rule:
83 * tXS-offset: tXS = tRFC+10ns.
84 * _____________________________
85 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
86 * XSOffset : | 7 | 8 | 9 | 10 | 11 | 12 |
87 */
88 static const u8 frq_xs_map[] = { 7, 8, 9, 10, 11, 12 };
89 xsoffset = frq_xs_map[get_FRQ(tCK, 100) - 7];
90 } else {
91 /* Get XSOffset based on MCU frequency using the following rule:
92 * ___________________________________
93 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
94 * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 14 |
95 */
96 static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11, 12, 14 };
97 xsoffset = frq_xs_map[get_FRQ(tCK, 133) - 3];
98 }
99
100 return xsoffset;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100101}
102
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100103static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100104{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100105 u8 mod;
106
107 if (base_freq == 100) {
108 /* Get MOD based on MCU frequency using the following rule:
109 * _____________________________
110 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
111 * MOD : | 12 | 12 | 14 | 15 | 17 | 18 |
112 */
113
114 static const u8 frq_mod_map[] = { 12, 12, 14, 15, 17, 18 };
115 mod = frq_mod_map[get_FRQ(tCK, 100) - 7];
116 } else {
117 /* Get MOD based on MCU frequency using the following rule:
118 * _______________________________________
119 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
120 * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | 18 | 20 |
121 */
122
123 static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16, 18, 20 };
124 mod = frq_mod_map[get_FRQ(tCK, 133) - 3];
125 }
126 return mod;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100127}
128
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100129static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100130{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100131 u8 wlo;
132
133 if (base_freq == 100) {
134 /* Get WLO based on MCU frequency using the following rule:
135 * Write leveling output delay
136 * _____________________________
137 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
138 * MOD : | 6 | 6 | 7 | 8 | 9 | 9 |
139 */
140
141 static const u8 frq_wlo_map[] = { 6, 6, 7, 8, 9, 9 };
142 wlo = frq_wlo_map[get_FRQ(tCK, 100) - 7];
143 } else {
144 /* Get WLO based on MCU frequency using the following rule:
145 * Write leveling output delay
146 * ________________________________
147 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
148 * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | 9 | 10 |
149 */
150 static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8, 9, 10 };
151 wlo = frq_wlo_map[get_FRQ(tCK, 133) - 3];
152 }
153
154 return wlo;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100155}
156
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100157static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100158{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100159 u8 cke;
160
161 if (base_freq == 100) {
162 /* Get CKE based on MCU frequency using the following rule:
163 * _____________________________
164 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
165 * MOD : | 4 | 4 | 5 | 5 | 6 | 6 |
166 */
167
168 static const u8 frq_cke_map[] = { 4, 4, 5, 5, 6, 6 };
169 cke = frq_cke_map[get_FRQ(tCK, 100) - 7];
170 } else {
171 /* Get CKE based on MCU frequency using the following rule:
172 * ________________________________
173 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
174 * WLO : | 3 | 3 | 4 | 4 | 5 | 6 | 6 | 7 |
175 */
176 static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6, 6, 7 };
177 cke = frq_cke_map[get_FRQ(tCK, 133) - 3];
178 }
179
180 return cke;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100181}
182
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100183static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100184{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100185 u8 xpdll;
186
187 if (base_freq == 100) {
188 /* Get XPDLL based on MCU frequency using the following rule:
189 * _____________________________
190 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
191 * XPDLL : | 17 | 20 | 22 | 24 | 27 | 32 |
192 */
193
194 static const u8 frq_xpdll_map[] = { 17, 20, 22, 24, 27, 32 };
195 xpdll = frq_xpdll_map[get_FRQ(tCK, 100) - 7];
196 } else {
197 /* Get XPDLL based on MCU frequency using the following rule:
198 * _______________________________________
199 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
200 * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | 29 | 32 |
201 */
202 static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26, 29, 32 };
203 xpdll = frq_xpdll_map[get_FRQ(tCK, 133) - 3];
204 }
205
206 return xpdll;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100207}
208
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100209static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100210{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100211 u8 xp;
212
213 if (base_freq == 100) {
214 /* Get XP based on MCU frequency using the following rule:
215 * _____________________________
216 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
217 * XP : | 5 | 5 | 6 | 6 | 7 | 8 |
218 */
219
220 static const u8 frq_xp_map[] = { 5, 5, 6, 6, 7, 8 };
221 xp = frq_xp_map[get_FRQ(tCK, 100) - 7];
222 } else {
223 /* Get XP based on MCU frequency using the following rule:
224 * _______________________________________
225 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
226 * XP : | 3 | 4 | 4 | 5 | 6 | 7 | 8 | 8 |
227 */
Elyes HAOUASa342f392018-10-17 10:56:26 +0200228 static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7, 8, 8 };
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100229 xp = frq_xp_map[get_FRQ(tCK, 133) - 3];
230 }
231
232 return xp;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100233}
234
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100235static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100236{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100237 u8 aonpd;
238
239 if (base_freq == 100) {
240 /* Get AONPD based on MCU frequency using the following rule:
241 * _____________________________
242 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
243 * AONPD : | 6 | 8 | 8 | 9 | 10 | 11 |
244 */
245
246 static const u8 frq_aonpd_map[] = { 6, 8, 8, 9, 10, 11 };
247 aonpd = frq_aonpd_map[get_FRQ(tCK, 100) - 7];
248 } else {
249 /* Get AONPD based on MCU frequency using the following rule:
250 * _______________________________________
251 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
252 * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | 11 | 12 |
253 */
254 static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10, 11, 12 };
255 aonpd = frq_aonpd_map[get_FRQ(tCK, 133) - 3];
256 }
257
258 return aonpd;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100259}
260
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100261static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100262{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100263 u32 comp2;
264
265 if (base_freq == 100) {
266 /* Get COMP2 based on MCU frequency using the following rule:
267 * ______________________________________________________________
268 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
269 * COMP : | CA8C264 | C6671E4 | C6671E4 | C446964 | C235924 | C235924 |
270 */
271
272 static const u32 frq_comp2_map[] = { 0xCA8C264, 0xC6671E4, 0xC6671E4, 0xC446964, 0xC235924, 0xC235924 };
273 comp2 = frq_comp2_map[get_FRQ(tCK, 100) - 7];
274 } else {
275 /* Get COMP2 based on MCU frequency using the following rule:
276 * ________________________________________________________________________________
277 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
278 * COMP : | D6FF5E4 | CEBDB64 | CA8C264 | C6671E4 | C446964 | C235924 | C235924 | C235924 |
279 */
280 static const u32 frq_comp2_map[] = { 0xD6FF5E4, 0xCEBDB64, 0xCA8C264,
281 0xC6671E4, 0xC446964, 0xC235924, 0xC235924, 0xC235924
282 };
283 comp2 = frq_comp2_map[get_FRQ(tCK, 133) - 3];
284 }
285
286 return comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100287}
288
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200289static void ivb_normalize_tclk(ramctr_timing *ctrl,
290 bool ref_100mhz_support)
291{
292 if (ctrl->tCK <= TCK_1200MHZ) {
293 ctrl->tCK = TCK_1200MHZ;
294 ctrl->base_freq = 100;
295 } else if (ctrl->tCK <= TCK_1100MHZ) {
296 ctrl->tCK = TCK_1100MHZ;
297 ctrl->base_freq = 100;
298 } else if (ctrl->tCK <= TCK_1066MHZ) {
299 ctrl->tCK = TCK_1066MHZ;
300 ctrl->base_freq = 133;
301 } else if (ctrl->tCK <= TCK_1000MHZ) {
302 ctrl->tCK = TCK_1000MHZ;
303 ctrl->base_freq = 100;
304 } else if (ctrl->tCK <= TCK_933MHZ) {
305 ctrl->tCK = TCK_933MHZ;
306 ctrl->base_freq = 133;
307 } else if (ctrl->tCK <= TCK_900MHZ) {
308 ctrl->tCK = TCK_900MHZ;
309 ctrl->base_freq = 100;
310 } else if (ctrl->tCK <= TCK_800MHZ) {
311 ctrl->tCK = TCK_800MHZ;
312 ctrl->base_freq = 133;
313 } else if (ctrl->tCK <= TCK_700MHZ) {
314 ctrl->tCK = TCK_700MHZ;
315 ctrl->base_freq = 100;
316 } else if (ctrl->tCK <= TCK_666MHZ) {
317 ctrl->tCK = TCK_666MHZ;
318 ctrl->base_freq = 133;
319 } else if (ctrl->tCK <= TCK_533MHZ) {
320 ctrl->tCK = TCK_533MHZ;
321 ctrl->base_freq = 133;
322 } else if (ctrl->tCK <= TCK_400MHZ) {
323 ctrl->tCK = TCK_400MHZ;
324 ctrl->base_freq = 133;
325 } else {
326 ctrl->tCK = 0;
327 return;
328 }
329
330 if (!ref_100mhz_support && ctrl->base_freq == 100) {
331 /* Skip unsupported frequency. */
332 ctrl->tCK++;
333 ivb_normalize_tclk(ctrl, ref_100mhz_support);
334 }
335}
336
337static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100338{
339 u8 val;
340 u32 val32;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200341 u32 reg32;
342 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100343
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200344 /* 100 Mhz reference clock supported */
345 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
346 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
347 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n",
348 ref_100mhz_support ? "yes" : "no");
349
350 /* Find CAS latency */
351 while (1) {
352 /* Normalising tCK before computing clock could potentially
353 * results in lower selected CAS, which is desired.
354 */
355 ivb_normalize_tclk(ctrl, ref_100mhz_support);
356 if (!(ctrl->tCK))
357 die("Couldn't find compatible clock / CAS settings\n");
358 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
359 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
360 for (; val <= MAX_CAS; val++)
361 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
362 break;
363 if (val == (MAX_CAS + 1)) {
364 ctrl->tCK++;
365 continue;
366 } else {
367 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
368 break;
369 }
370 }
371
372 val32 = NS2MHZ_DIV256 / ctrl->tCK;
373 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
374
375 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
376 ctrl->CAS = val;
377}
378
379
380static void dram_timing(ramctr_timing *ctrl)
381{
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100382 /* Maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
383 * We cap it at 1200Mhz (DDR3 2400).
Patrick Rudolph305035c2016-11-11 18:38:50 +0100384 * Then, align it to the closest JEDEC standard frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200385 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100386 ctrl->edge_offset[0] = 18; //XXX: guessed
387 ctrl->edge_offset[1] = 8;
388 ctrl->edge_offset[2] = 8;
389 ctrl->timC_offset[0] = 20; //XXX: guessed
390 ctrl->timC_offset[1] = 8;
391 ctrl->timC_offset[2] = 8;
392 ctrl->reg_320c_range_threshold = 10;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200393 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100394 ctrl->edge_offset[0] = 17; //XXX: guessed
395 ctrl->edge_offset[1] = 7;
396 ctrl->edge_offset[2] = 7;
397 ctrl->timC_offset[0] = 19; //XXX: guessed
398 ctrl->timC_offset[1] = 7;
399 ctrl->timC_offset[2] = 7;
400 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200401 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100402 ctrl->edge_offset[0] = 16;
403 ctrl->edge_offset[1] = 7;
404 ctrl->edge_offset[2] = 7;
405 ctrl->timC_offset[0] = 18;
406 ctrl->timC_offset[1] = 7;
407 ctrl->timC_offset[2] = 7;
408 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200409 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100410 ctrl->edge_offset[0] = 15; //XXX: guessed
411 ctrl->edge_offset[1] = 6;
412 ctrl->edge_offset[2] = 6;
413 ctrl->timC_offset[0] = 17; //XXX: guessed
414 ctrl->timC_offset[1] = 6;
415 ctrl->timC_offset[2] = 6;
416 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200417 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100418 ctrl->edge_offset[0] = 14;
419 ctrl->edge_offset[1] = 6;
420 ctrl->edge_offset[2] = 6;
421 ctrl->timC_offset[0] = 15;
422 ctrl->timC_offset[1] = 6;
423 ctrl->timC_offset[2] = 6;
424 ctrl->reg_320c_range_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200425 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100426 ctrl->edge_offset[0] = 14; //XXX: guessed
427 ctrl->edge_offset[1] = 6;
428 ctrl->edge_offset[2] = 6;
429 ctrl->timC_offset[0] = 15; //XXX: guessed
430 ctrl->timC_offset[1] = 6;
431 ctrl->timC_offset[2] = 6;
432 ctrl->reg_320c_range_threshold = 12;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200433 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100434 ctrl->edge_offset[0] = 13;
435 ctrl->edge_offset[1] = 5;
436 ctrl->edge_offset[2] = 5;
437 ctrl->timC_offset[0] = 14;
438 ctrl->timC_offset[1] = 5;
439 ctrl->timC_offset[2] = 5;
440 ctrl->reg_320c_range_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200441 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100442 ctrl->edge_offset[0] = 13; //XXX: guessed
443 ctrl->edge_offset[1] = 5;
444 ctrl->edge_offset[2] = 5;
445 ctrl->timC_offset[0] = 14; //XXX: guessed
446 ctrl->timC_offset[1] = 5;
447 ctrl->timC_offset[2] = 5;
448 ctrl->reg_320c_range_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200449 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100450 ctrl->edge_offset[0] = 10;
451 ctrl->edge_offset[1] = 4;
452 ctrl->edge_offset[2] = 4;
453 ctrl->timC_offset[0] = 11;
454 ctrl->timC_offset[1] = 4;
455 ctrl->timC_offset[2] = 4;
456 ctrl->reg_320c_range_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200457 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100458 ctrl->edge_offset[0] = 8;
459 ctrl->edge_offset[1] = 3;
460 ctrl->edge_offset[2] = 3;
461 ctrl->timC_offset[0] = 9;
462 ctrl->timC_offset[1] = 3;
463 ctrl->timC_offset[2] = 3;
464 ctrl->reg_320c_range_threshold = 17;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200465 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100466 ctrl->edge_offset[0] = 6;
467 ctrl->edge_offset[1] = 2;
468 ctrl->edge_offset[2] = 2;
469 ctrl->timC_offset[0] = 6;
470 ctrl->timC_offset[1] = 2;
471 ctrl->timC_offset[2] = 2;
472 ctrl->reg_320c_range_threshold = 17;
473 }
474
475 /* Initial phase between CLK/CMD pins */
476 ctrl->reg_c14_offset = (256000 / ctrl->tCK) / 66;
477
478 /* DLL_CONFIG_MDLL_W_TIMER */
479 ctrl->reg_5064b0 = (128000 / ctrl->tCK) + 3;
480
Dan Elkoubydabebc32018-04-13 18:47:10 +0300481 if (ctrl->tCWL)
482 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
483 else
484 ctrl->CWL = get_CWL(ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100485 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
486
487 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100488 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100489 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
490
Arthur Heymans50db9c92017-03-23 18:53:38 +0100491 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100492 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
493
494 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100495 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100496 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
497
498 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100499 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100500 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
501
502 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100503 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100504 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
505
506 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100507 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100508 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
509
510 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100511 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100512 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
513
514 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100515 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100516 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
517
518 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100519 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100520 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
521
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100522 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
523 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
524 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
525 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
526 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
527 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
528 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
529 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100530}
531
532static void dram_freq(ramctr_timing * ctrl)
533{
534 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100535 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
536 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100537 ctrl->tCK = TCK_400MHZ;
538 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100539
Patrick Rudolph305035c2016-11-11 18:38:50 +0100540 while (1) {
541 u8 val2;
542 u32 reg1 = 0;
543
544 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200545 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100546
Patrick Rudolph305035c2016-11-11 18:38:50 +0100547 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100548 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100549
550 /* The PLL will never lock if the required frequency is
551 * already set. Exit early to prevent a system hang.
552 */
553 reg1 = MCHBAR32(MC_BIOS_DATA);
554 val2 = (u8) reg1;
555 if (val2)
556 return;
557
558 /* Step 2 - Select frequency in the MCU */
559 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100560 if (ctrl->base_freq == 100)
561 reg1 |= 0x100; /* Enable 100Mhz REF clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100562 reg1 |= 0x80000000; // set running bit
563 MCHBAR32(MC_BIOS_REQ) = reg1;
564 int i=0;
565 printk(BIOS_DEBUG, "PLL busy... ");
566 while (reg1 & 0x80000000) {
567 udelay(10);
568 i++;
569 reg1 = MCHBAR32(MC_BIOS_REQ);
570 }
571 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
572
573 /* Step 3 - Verify lock frequency */
574 reg1 = MCHBAR32(MC_BIOS_DATA);
575 val2 = (u8) reg1;
576 if (val2 >= FRQ) {
577 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
578 (1000 << 8) / ctrl->tCK);
579 return;
580 }
581 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
582 ctrl->tCK++;
583 }
584}
585
586static void dram_ioregs(ramctr_timing * ctrl)
587{
588 u32 reg, comp2;
589
590 int channel;
591
592 // IO clock
593 FOR_ALL_CHANNELS {
594 MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel];
595 }
596
597 // IO command
598 FOR_ALL_CHANNELS {
599 MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel];
600 }
601
602 // IO control
603 FOR_ALL_POPULATED_CHANNELS {
604 program_timings(ctrl, channel);
605 }
606
607 // Rcomp
608 printram("RCOMP...");
609 reg = 0;
610 while (reg == 0) {
611 reg = MCHBAR32(0x5084) & 0x10000;
612 }
613 printram("done\n");
614
615 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100616 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100617 MCHBAR32(0x3714) = comp2;
618 printram("COMP2 done\n");
619
620 // Set comp1
621 FOR_ALL_POPULATED_CHANNELS {
622 reg = MCHBAR32(0x1810 + channel * 0x100); //ch0
623 reg = (reg & ~0xe00) | (1 << 9); //odt
624 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
625 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
626 MCHBAR32(0x1810 + channel * 0x100) = reg;
627 }
628 printram("COMP1 done\n");
629
630 printram("FORCE RCOMP and wait 20us...");
631 MCHBAR32(0x5f08) |= 0x100;
632 udelay(20);
633 printram("done\n");
634}
635
636int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
637 int s3_resume, int me_uma_size)
638{
639 int err;
640
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100641 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
642 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100643
644 if (!fast_boot) {
645 /* Find fastest common supported parameters */
646 dram_find_common_params(ctrl);
647
648 dram_dimm_mapping(ctrl);
649 }
650
651 /* Set MCU frequency */
652 dram_freq(ctrl);
653
654 if (!fast_boot) {
655 /* Calculate timings */
656 dram_timing(ctrl);
657 }
658
659 /* Set version register */
660 MCHBAR32(0x5034) = 0xC04EB002;
661
662 /* Enable crossover */
663 dram_xover(ctrl);
664
665 /* Set timing and refresh registers */
666 dram_timing_regs(ctrl);
667
668 /* Power mode preset */
669 MCHBAR32(0x4e80) = 0x5500;
670
671 /* Set scheduler parameters */
672 MCHBAR32(0x4c20) = 0x10100005;
673
674 /* Set CPU specific register */
675 set_4f8c();
676
677 /* Clear IO reset bit */
678 MCHBAR32(0x5030) &= ~0x20;
679
680 /* Set MAD-DIMM registers */
681 dram_dimm_set_mapping(ctrl);
682 printk(BIOS_DEBUG, "Done dimm mapping\n");
683
684 /* Zone config */
685 dram_zones(ctrl, 1);
686
687 /* Set memory map */
688 dram_memorymap(ctrl, me_uma_size);
689 printk(BIOS_DEBUG, "Done memory map\n");
690
691 /* Set IO registers */
692 dram_ioregs(ctrl);
693 printk(BIOS_DEBUG, "Done io registers\n");
694
695 udelay(1);
696
697 if (fast_boot) {
698 restore_timings(ctrl);
699 } else {
700 /* Do jedec ddr3 reset sequence */
701 dram_jedecreset(ctrl);
702 printk(BIOS_DEBUG, "Done jedec reset\n");
703
704 /* MRS commands */
705 dram_mrscommands(ctrl);
706 printk(BIOS_DEBUG, "Done MRS commands\n");
707
708 /* Prepare for memory training */
709 prepare_training(ctrl);
710
711 err = read_training(ctrl);
712 if (err)
713 return err;
714
715 err = write_training(ctrl);
716 if (err)
717 return err;
718
719 printram("CP5a\n");
720
721 err = discover_edges(ctrl);
722 if (err)
723 return err;
724
725 printram("CP5b\n");
726
727 err = command_training(ctrl);
728 if (err)
729 return err;
730
731 printram("CP5c\n");
732
733 err = discover_edges_write(ctrl);
734 if (err)
735 return err;
736
737 err = discover_timC_write(ctrl);
738 if (err)
739 return err;
740
741 normalize_training(ctrl);
742 }
743
744 set_4008c(ctrl);
745
746 write_controller_mr(ctrl);
747
748 if (!s3_resume) {
749 err = channel_test(ctrl);
750 if (err)
751 return err;
752 }
753
754 return 0;
755}