blob: 8013636f92bd5faee396825759edd6a76270b55d [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 <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010022#include "raminit_native.h"
23#include "raminit_common.h"
24
25/* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010026static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010027{
28 u32 FRQ;
Patrick Rudolph77eaba32016-11-11 18:55:54 +010029
30 FRQ = 256000 / (tCK * base_freq);
31
32 if (base_freq == 100) {
33 if (FRQ > 12)
34 return 12;
35 if (FRQ < 7)
36 return 7;
37 } else {
38 if (FRQ > 10)
39 return 10;
40 if (FRQ < 3)
41 return 3;
42 }
43
Patrick Rudolph305035c2016-11-11 18:38:50 +010044 return FRQ;
45}
46
Patrick Rudolph77eaba32016-11-11 18:55:54 +010047static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010048{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010049 u32 refi;
50
51 if (base_freq == 100) {
52 /* Get REFI based on MCU frequency using the following rule:
53 * tREFI = 7.8usec
54 * _________________________________________
55 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
56 * REFI : | 5460 | 6240 | 7020 | 7800 | 8580 | 9360 |
57 */
58 static const u32 frq_xs_map[] =
59 { 5460, 6240, 7020, 7800, 8580, 9360 };
60 refi = frq_xs_map[get_FRQ(tCK, 100) - 7];
61 } else {
62 /* Get REFI based on MCU frequency using the following rule:
63 * tREFI = 7.8usec
64 * ________________________________________________________
65 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
66 * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | 9360 | 10400 |
67 */
68 static const u32 frq_refi_map[] =
69 { 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400 };
70 refi = frq_refi_map[get_FRQ(tCK, 133) - 3];
71 }
72
73 return refi;
Patrick Rudolph305035c2016-11-11 18:38:50 +010074}
75
Patrick Rudolph77eaba32016-11-11 18:55:54 +010076static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010077{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010078 u8 xsoffset;
79
80 if (base_freq == 100) {
81 /* Get XSOffset based on MCU frequency using the following rule:
82 * tXS-offset: tXS = tRFC+10ns.
83 * _____________________________
84 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
85 * XSOffset : | 7 | 8 | 9 | 10 | 11 | 12 |
86 */
87 static const u8 frq_xs_map[] = { 7, 8, 9, 10, 11, 12 };
88 xsoffset = frq_xs_map[get_FRQ(tCK, 100) - 7];
89 } else {
90 /* Get XSOffset based on MCU frequency using the following rule:
91 * ___________________________________
92 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
93 * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 14 |
94 */
95 static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11, 12, 14 };
96 xsoffset = frq_xs_map[get_FRQ(tCK, 133) - 3];
97 }
98
99 return xsoffset;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100100}
101
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100102static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100103{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100104 u8 mod;
105
106 if (base_freq == 100) {
107 /* Get MOD based on MCU frequency using the following rule:
108 * _____________________________
109 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
110 * MOD : | 12 | 12 | 14 | 15 | 17 | 18 |
111 */
112
113 static const u8 frq_mod_map[] = { 12, 12, 14, 15, 17, 18 };
114 mod = frq_mod_map[get_FRQ(tCK, 100) - 7];
115 } else {
116 /* Get MOD based on MCU frequency using the following rule:
117 * _______________________________________
118 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
119 * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | 18 | 20 |
120 */
121
122 static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16, 18, 20 };
123 mod = frq_mod_map[get_FRQ(tCK, 133) - 3];
124 }
125 return mod;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100126}
127
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100128static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100129{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100130 u8 wlo;
131
132 if (base_freq == 100) {
133 /* Get WLO based on MCU frequency using the following rule:
134 * Write leveling output delay
135 * _____________________________
136 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
137 * MOD : | 6 | 6 | 7 | 8 | 9 | 9 |
138 */
139
140 static const u8 frq_wlo_map[] = { 6, 6, 7, 8, 9, 9 };
141 wlo = frq_wlo_map[get_FRQ(tCK, 100) - 7];
142 } else {
143 /* Get WLO based on MCU frequency using the following rule:
144 * Write leveling output delay
145 * ________________________________
146 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
147 * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | 9 | 10 |
148 */
149 static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8, 9, 10 };
150 wlo = frq_wlo_map[get_FRQ(tCK, 133) - 3];
151 }
152
153 return wlo;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100154}
155
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100156static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100157{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100158 u8 cke;
159
160 if (base_freq == 100) {
161 /* Get CKE based on MCU frequency using the following rule:
162 * _____________________________
163 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
164 * MOD : | 4 | 4 | 5 | 5 | 6 | 6 |
165 */
166
167 static const u8 frq_cke_map[] = { 4, 4, 5, 5, 6, 6 };
168 cke = frq_cke_map[get_FRQ(tCK, 100) - 7];
169 } else {
170 /* Get CKE based on MCU frequency using the following rule:
171 * ________________________________
172 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
173 * WLO : | 3 | 3 | 4 | 4 | 5 | 6 | 6 | 7 |
174 */
175 static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6, 6, 7 };
176 cke = frq_cke_map[get_FRQ(tCK, 133) - 3];
177 }
178
179 return cke;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100180}
181
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100182static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100183{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100184 u8 xpdll;
185
186 if (base_freq == 100) {
187 /* Get XPDLL based on MCU frequency using the following rule:
188 * _____________________________
189 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
190 * XPDLL : | 17 | 20 | 22 | 24 | 27 | 32 |
191 */
192
193 static const u8 frq_xpdll_map[] = { 17, 20, 22, 24, 27, 32 };
194 xpdll = frq_xpdll_map[get_FRQ(tCK, 100) - 7];
195 } else {
196 /* Get XPDLL based on MCU frequency using the following rule:
197 * _______________________________________
198 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
199 * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | 29 | 32 |
200 */
201 static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26, 29, 32 };
202 xpdll = frq_xpdll_map[get_FRQ(tCK, 133) - 3];
203 }
204
205 return xpdll;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100206}
207
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100208static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100209{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100210 u8 xp;
211
212 if (base_freq == 100) {
213 /* Get XP based on MCU frequency using the following rule:
214 * _____________________________
215 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
216 * XP : | 5 | 5 | 6 | 6 | 7 | 8 |
217 */
218
219 static const u8 frq_xp_map[] = { 5, 5, 6, 6, 7, 8 };
220 xp = frq_xp_map[get_FRQ(tCK, 100) - 7];
221 } else {
222 /* Get XP based on MCU frequency using the following rule:
223 * _______________________________________
224 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
225 * XP : | 3 | 4 | 4 | 5 | 6 | 7 | 8 | 8 |
226 */
Elyes HAOUASa342f392018-10-17 10:56:26 +0200227 static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7, 8, 8 };
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100228 xp = frq_xp_map[get_FRQ(tCK, 133) - 3];
229 }
230
231 return xp;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100232}
233
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100234static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100235{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100236 u8 aonpd;
237
238 if (base_freq == 100) {
239 /* Get AONPD based on MCU frequency using the following rule:
240 * _____________________________
241 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
242 * AONPD : | 6 | 8 | 8 | 9 | 10 | 11 |
243 */
244
245 static const u8 frq_aonpd_map[] = { 6, 8, 8, 9, 10, 11 };
246 aonpd = frq_aonpd_map[get_FRQ(tCK, 100) - 7];
247 } else {
248 /* Get AONPD based on MCU frequency using the following rule:
249 * _______________________________________
250 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
251 * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | 11 | 12 |
252 */
253 static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10, 11, 12 };
254 aonpd = frq_aonpd_map[get_FRQ(tCK, 133) - 3];
255 }
256
257 return aonpd;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100258}
259
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100260static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100261{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100262 u32 comp2;
263
264 if (base_freq == 100) {
265 /* Get COMP2 based on MCU frequency using the following rule:
266 * ______________________________________________________________
267 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
268 * COMP : | CA8C264 | C6671E4 | C6671E4 | C446964 | C235924 | C235924 |
269 */
270
271 static const u32 frq_comp2_map[] = { 0xCA8C264, 0xC6671E4, 0xC6671E4, 0xC446964, 0xC235924, 0xC235924 };
272 comp2 = frq_comp2_map[get_FRQ(tCK, 100) - 7];
273 } else {
274 /* Get COMP2 based on MCU frequency using the following rule:
275 * ________________________________________________________________________________
276 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
277 * COMP : | D6FF5E4 | CEBDB64 | CA8C264 | C6671E4 | C446964 | C235924 | C235924 | C235924 |
278 */
279 static const u32 frq_comp2_map[] = { 0xD6FF5E4, 0xCEBDB64, 0xCA8C264,
280 0xC6671E4, 0xC446964, 0xC235924, 0xC235924, 0xC235924
281 };
282 comp2 = frq_comp2_map[get_FRQ(tCK, 133) - 3];
283 }
284
285 return comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100286}
287
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200288static void ivb_normalize_tclk(ramctr_timing *ctrl,
289 bool ref_100mhz_support)
290{
291 if (ctrl->tCK <= TCK_1200MHZ) {
292 ctrl->tCK = TCK_1200MHZ;
293 ctrl->base_freq = 100;
294 } else if (ctrl->tCK <= TCK_1100MHZ) {
295 ctrl->tCK = TCK_1100MHZ;
296 ctrl->base_freq = 100;
297 } else if (ctrl->tCK <= TCK_1066MHZ) {
298 ctrl->tCK = TCK_1066MHZ;
299 ctrl->base_freq = 133;
300 } else if (ctrl->tCK <= TCK_1000MHZ) {
301 ctrl->tCK = TCK_1000MHZ;
302 ctrl->base_freq = 100;
303 } else if (ctrl->tCK <= TCK_933MHZ) {
304 ctrl->tCK = TCK_933MHZ;
305 ctrl->base_freq = 133;
306 } else if (ctrl->tCK <= TCK_900MHZ) {
307 ctrl->tCK = TCK_900MHZ;
308 ctrl->base_freq = 100;
309 } else if (ctrl->tCK <= TCK_800MHZ) {
310 ctrl->tCK = TCK_800MHZ;
311 ctrl->base_freq = 133;
312 } else if (ctrl->tCK <= TCK_700MHZ) {
313 ctrl->tCK = TCK_700MHZ;
314 ctrl->base_freq = 100;
315 } else if (ctrl->tCK <= TCK_666MHZ) {
316 ctrl->tCK = TCK_666MHZ;
317 ctrl->base_freq = 133;
318 } else if (ctrl->tCK <= TCK_533MHZ) {
319 ctrl->tCK = TCK_533MHZ;
320 ctrl->base_freq = 133;
321 } else if (ctrl->tCK <= TCK_400MHZ) {
322 ctrl->tCK = TCK_400MHZ;
323 ctrl->base_freq = 133;
324 } else {
325 ctrl->tCK = 0;
326 return;
327 }
328
329 if (!ref_100mhz_support && ctrl->base_freq == 100) {
330 /* Skip unsupported frequency. */
331 ctrl->tCK++;
332 ivb_normalize_tclk(ctrl, ref_100mhz_support);
333 }
334}
335
336static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100337{
338 u8 val;
339 u32 val32;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200340 u32 reg32;
341 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100342
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200343 /* 100 Mhz reference clock supported */
344 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
345 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
346 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n",
347 ref_100mhz_support ? "yes" : "no");
348
349 /* Find CAS latency */
350 while (1) {
351 /* Normalising tCK before computing clock could potentially
352 * results in lower selected CAS, which is desired.
353 */
354 ivb_normalize_tclk(ctrl, ref_100mhz_support);
355 if (!(ctrl->tCK))
356 die("Couldn't find compatible clock / CAS settings\n");
357 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
358 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
359 for (; val <= MAX_CAS; val++)
360 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
361 break;
362 if (val == (MAX_CAS + 1)) {
363 ctrl->tCK++;
364 continue;
365 } else {
366 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
367 break;
368 }
369 }
370
371 val32 = NS2MHZ_DIV256 / ctrl->tCK;
372 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
373
374 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
375 ctrl->CAS = val;
376}
377
378
379static void dram_timing(ramctr_timing *ctrl)
380{
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100381 /* Maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
382 * We cap it at 1200Mhz (DDR3 2400).
Patrick Rudolph305035c2016-11-11 18:38:50 +0100383 * Then, align it to the closest JEDEC standard frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200384 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100385 ctrl->edge_offset[0] = 18; //XXX: guessed
386 ctrl->edge_offset[1] = 8;
387 ctrl->edge_offset[2] = 8;
388 ctrl->timC_offset[0] = 20; //XXX: guessed
389 ctrl->timC_offset[1] = 8;
390 ctrl->timC_offset[2] = 8;
Angel Pons88521882020-01-05 20:21:20 +0100391 ctrl->pi_coding_threshold = 10;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200392 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100393 ctrl->edge_offset[0] = 17; //XXX: guessed
394 ctrl->edge_offset[1] = 7;
395 ctrl->edge_offset[2] = 7;
396 ctrl->timC_offset[0] = 19; //XXX: guessed
397 ctrl->timC_offset[1] = 7;
398 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100399 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200400 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100401 ctrl->edge_offset[0] = 16;
402 ctrl->edge_offset[1] = 7;
403 ctrl->edge_offset[2] = 7;
404 ctrl->timC_offset[0] = 18;
405 ctrl->timC_offset[1] = 7;
406 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100407 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200408 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100409 ctrl->edge_offset[0] = 15; //XXX: guessed
410 ctrl->edge_offset[1] = 6;
411 ctrl->edge_offset[2] = 6;
412 ctrl->timC_offset[0] = 17; //XXX: guessed
413 ctrl->timC_offset[1] = 6;
414 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100415 ctrl->pi_coding_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200416 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100417 ctrl->edge_offset[0] = 14;
418 ctrl->edge_offset[1] = 6;
419 ctrl->edge_offset[2] = 6;
420 ctrl->timC_offset[0] = 15;
421 ctrl->timC_offset[1] = 6;
422 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100423 ctrl->pi_coding_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200424 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100425 ctrl->edge_offset[0] = 14; //XXX: guessed
426 ctrl->edge_offset[1] = 6;
427 ctrl->edge_offset[2] = 6;
428 ctrl->timC_offset[0] = 15; //XXX: guessed
429 ctrl->timC_offset[1] = 6;
430 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100431 ctrl->pi_coding_threshold = 12;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200432 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100433 ctrl->edge_offset[0] = 13;
434 ctrl->edge_offset[1] = 5;
435 ctrl->edge_offset[2] = 5;
436 ctrl->timC_offset[0] = 14;
437 ctrl->timC_offset[1] = 5;
438 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100439 ctrl->pi_coding_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200440 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100441 ctrl->edge_offset[0] = 13; //XXX: guessed
442 ctrl->edge_offset[1] = 5;
443 ctrl->edge_offset[2] = 5;
444 ctrl->timC_offset[0] = 14; //XXX: guessed
445 ctrl->timC_offset[1] = 5;
446 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100447 ctrl->pi_coding_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200448 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100449 ctrl->edge_offset[0] = 10;
450 ctrl->edge_offset[1] = 4;
451 ctrl->edge_offset[2] = 4;
452 ctrl->timC_offset[0] = 11;
453 ctrl->timC_offset[1] = 4;
454 ctrl->timC_offset[2] = 4;
Angel Pons88521882020-01-05 20:21:20 +0100455 ctrl->pi_coding_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200456 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100457 ctrl->edge_offset[0] = 8;
458 ctrl->edge_offset[1] = 3;
459 ctrl->edge_offset[2] = 3;
460 ctrl->timC_offset[0] = 9;
461 ctrl->timC_offset[1] = 3;
462 ctrl->timC_offset[2] = 3;
Angel Pons88521882020-01-05 20:21:20 +0100463 ctrl->pi_coding_threshold = 17;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200464 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100465 ctrl->edge_offset[0] = 6;
466 ctrl->edge_offset[1] = 2;
467 ctrl->edge_offset[2] = 2;
468 ctrl->timC_offset[0] = 6;
469 ctrl->timC_offset[1] = 2;
470 ctrl->timC_offset[2] = 2;
Angel Pons88521882020-01-05 20:21:20 +0100471 ctrl->pi_coding_threshold = 17;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100472 }
473
474 /* Initial phase between CLK/CMD pins */
Angel Pons88521882020-01-05 20:21:20 +0100475 ctrl->pi_code_offset = (256000 / ctrl->tCK) / 66;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100476
477 /* DLL_CONFIG_MDLL_W_TIMER */
Angel Pons88521882020-01-05 20:21:20 +0100478 ctrl->mdll_wake_delay = (128000 / ctrl->tCK) + 3;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100479
Dan Elkoubydabebc32018-04-13 18:47:10 +0300480 if (ctrl->tCWL)
481 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
482 else
483 ctrl->CWL = get_CWL(ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100484 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
485
486 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100487 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100488 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
489
Arthur Heymans50db9c92017-03-23 18:53:38 +0100490 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100491 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
492
493 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100494 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100495 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
496
497 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100498 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100499 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
500
501 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100502 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100503 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
504
505 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100506 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100507 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
508
509 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100510 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100511 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
512
513 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100514 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100515 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
516
517 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100518 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100519 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
520
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100521 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
522 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
523 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
524 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
525 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
526 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
527 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
528 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100529}
530
Angel Pons88521882020-01-05 20:21:20 +0100531static void dram_freq(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100532{
533 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100534 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
535 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100536 ctrl->tCK = TCK_400MHZ;
537 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100538
Patrick Rudolph305035c2016-11-11 18:38:50 +0100539 while (1) {
540 u8 val2;
541 u32 reg1 = 0;
542
543 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200544 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100545
Patrick Rudolph305035c2016-11-11 18:38:50 +0100546 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100547 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100548
549 /* The PLL will never lock if the required frequency is
550 * already set. Exit early to prevent a system hang.
551 */
552 reg1 = MCHBAR32(MC_BIOS_DATA);
553 val2 = (u8) reg1;
554 if (val2)
555 return;
556
557 /* Step 2 - Select frequency in the MCU */
558 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100559 if (ctrl->base_freq == 100)
560 reg1 |= 0x100; /* Enable 100Mhz REF clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100561 reg1 |= 0x80000000; // set running bit
562 MCHBAR32(MC_BIOS_REQ) = reg1;
563 int i=0;
564 printk(BIOS_DEBUG, "PLL busy... ");
565 while (reg1 & 0x80000000) {
566 udelay(10);
567 i++;
568 reg1 = MCHBAR32(MC_BIOS_REQ);
569 }
570 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
571
572 /* Step 3 - Verify lock frequency */
573 reg1 = MCHBAR32(MC_BIOS_DATA);
574 val2 = (u8) reg1;
575 if (val2 >= FRQ) {
576 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
577 (1000 << 8) / ctrl->tCK);
578 return;
579 }
580 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
581 ctrl->tCK++;
582 }
583}
584
Angel Pons88521882020-01-05 20:21:20 +0100585static void dram_ioregs(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100586{
587 u32 reg, comp2;
588
589 int channel;
590
591 // IO clock
592 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100593 MCHBAR32(GDCRCLKRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100594 }
595
596 // IO command
597 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100598 MCHBAR32(GDCRCTLRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100599 }
600
601 // IO control
602 FOR_ALL_POPULATED_CHANNELS {
603 program_timings(ctrl, channel);
604 }
605
606 // Rcomp
607 printram("RCOMP...");
608 reg = 0;
609 while (reg == 0) {
Angel Pons88521882020-01-05 20:21:20 +0100610 reg = MCHBAR32(RCOMP_TIMER) & 0x10000;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100611 }
612 printram("done\n");
613
614 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100615 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Angel Pons88521882020-01-05 20:21:20 +0100616 MCHBAR32(CRCOMPOFST2) = comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100617 printram("COMP2 done\n");
618
619 // Set comp1
620 FOR_ALL_POPULATED_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100621 reg = MCHBAR32(CRCOMPOFST1_ch(channel)); //ch0
Patrick Rudolph305035c2016-11-11 18:38:50 +0100622 reg = (reg & ~0xe00) | (1 << 9); //odt
623 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
624 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
Angel Pons88521882020-01-05 20:21:20 +0100625 MCHBAR32(CRCOMPOFST1_ch(channel)) = reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100626 }
627 printram("COMP1 done\n");
628
629 printram("FORCE RCOMP and wait 20us...");
Angel Pons88521882020-01-05 20:21:20 +0100630 MCHBAR32(M_COMP) |= 0x100;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100631 udelay(20);
632 printram("done\n");
633}
634
635int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
636 int s3_resume, int me_uma_size)
637{
638 int err;
639
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100640 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
641 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100642
643 if (!fast_boot) {
644 /* Find fastest common supported parameters */
645 dram_find_common_params(ctrl);
646
647 dram_dimm_mapping(ctrl);
648 }
649
650 /* Set MCU frequency */
651 dram_freq(ctrl);
652
653 if (!fast_boot) {
654 /* Calculate timings */
655 dram_timing(ctrl);
656 }
657
658 /* Set version register */
Angel Pons88521882020-01-05 20:21:20 +0100659 MCHBAR32(MRC_REVISION) = 0xC04EB002;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100660
661 /* Enable crossover */
662 dram_xover(ctrl);
663
664 /* Set timing and refresh registers */
665 dram_timing_regs(ctrl);
666
667 /* Power mode preset */
Angel Pons88521882020-01-05 20:21:20 +0100668 MCHBAR32(PM_THML_STAT) = 0x5500;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100669
Angel Pons88521882020-01-05 20:21:20 +0100670 /* Set scheduler chicken bits */
671 MCHBAR32(SCHED_CBIT) = 0x10100005;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100672
673 /* Set CPU specific register */
674 set_4f8c();
675
676 /* Clear IO reset bit */
Angel Pons88521882020-01-05 20:21:20 +0100677 MCHBAR32(MC_INIT_STATE_G) &= ~0x20;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100678
679 /* Set MAD-DIMM registers */
680 dram_dimm_set_mapping(ctrl);
681 printk(BIOS_DEBUG, "Done dimm mapping\n");
682
683 /* Zone config */
684 dram_zones(ctrl, 1);
685
686 /* Set memory map */
687 dram_memorymap(ctrl, me_uma_size);
688 printk(BIOS_DEBUG, "Done memory map\n");
689
690 /* Set IO registers */
691 dram_ioregs(ctrl);
692 printk(BIOS_DEBUG, "Done io registers\n");
693
694 udelay(1);
695
696 if (fast_boot) {
697 restore_timings(ctrl);
698 } else {
699 /* Do jedec ddr3 reset sequence */
700 dram_jedecreset(ctrl);
701 printk(BIOS_DEBUG, "Done jedec reset\n");
702
703 /* MRS commands */
704 dram_mrscommands(ctrl);
705 printk(BIOS_DEBUG, "Done MRS commands\n");
706
707 /* Prepare for memory training */
708 prepare_training(ctrl);
709
710 err = read_training(ctrl);
711 if (err)
712 return err;
713
714 err = write_training(ctrl);
715 if (err)
716 return err;
717
718 printram("CP5a\n");
719
720 err = discover_edges(ctrl);
721 if (err)
722 return err;
723
724 printram("CP5b\n");
725
726 err = command_training(ctrl);
727 if (err)
728 return err;
729
730 printram("CP5c\n");
731
732 err = discover_edges_write(ctrl);
733 if (err)
734 return err;
735
736 err = discover_timC_write(ctrl);
737 if (err)
738 return err;
739
740 normalize_training(ctrl);
741 }
742
743 set_4008c(ctrl);
744
745 write_controller_mr(ctrl);
746
747 if (!s3_resume) {
748 err = channel_test(ctrl);
749 if (err)
750 return err;
751 }
752
753 return 0;
754}