blob: cee7eddfb8164cef59a53137b72543d9f6afc9db [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>
20#include <cpu/x86/msr.h>
21#include <delay.h>
22#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 */
227 static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 , 8, 8 };
228 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
288static void dram_timing(ramctr_timing * ctrl)
289{
290 u8 val;
291 u32 val32;
292
293 /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure
294 * we cap it if we have faster DIMMs.
295 * Then, align it to the closest JEDEC standard frequency */
296 if (ctrl->tCK <= TCK_1066MHZ) {
297 ctrl->tCK = TCK_1066MHZ;
298 ctrl->edge_offset[0] = 16;
299 ctrl->edge_offset[1] = 7;
300 ctrl->edge_offset[2] = 7;
301 ctrl->timC_offset[0] = 18;
302 ctrl->timC_offset[1] = 7;
303 ctrl->timC_offset[2] = 7;
304 ctrl->reg_320c_range_threshold = 13;
305 } else if (ctrl->tCK <= TCK_933MHZ) {
306 ctrl->tCK = TCK_933MHZ;
307 ctrl->edge_offset[0] = 14;
308 ctrl->edge_offset[1] = 6;
309 ctrl->edge_offset[2] = 6;
310 ctrl->timC_offset[0] = 15;
311 ctrl->timC_offset[1] = 6;
312 ctrl->timC_offset[2] = 6;
313 ctrl->reg_320c_range_threshold = 15;
314 } else if (ctrl->tCK <= TCK_800MHZ) {
315 ctrl->tCK = TCK_800MHZ;
316 ctrl->edge_offset[0] = 13;
317 ctrl->edge_offset[1] = 5;
318 ctrl->edge_offset[2] = 5;
319 ctrl->timC_offset[0] = 14;
320 ctrl->timC_offset[1] = 5;
321 ctrl->timC_offset[2] = 5;
322 ctrl->reg_320c_range_threshold = 15;
323 } else if (ctrl->tCK <= TCK_666MHZ) {
324 ctrl->tCK = TCK_666MHZ;
325 ctrl->edge_offset[0] = 10;
326 ctrl->edge_offset[1] = 4;
327 ctrl->edge_offset[2] = 4;
328 ctrl->timC_offset[0] = 11;
329 ctrl->timC_offset[1] = 4;
330 ctrl->timC_offset[2] = 4;
331 ctrl->reg_320c_range_threshold = 16;
332 } else if (ctrl->tCK <= TCK_533MHZ) {
333 ctrl->tCK = TCK_533MHZ;
334 ctrl->edge_offset[0] = 8;
335 ctrl->edge_offset[1] = 3;
336 ctrl->edge_offset[2] = 3;
337 ctrl->timC_offset[0] = 9;
338 ctrl->timC_offset[1] = 3;
339 ctrl->timC_offset[2] = 3;
340 ctrl->reg_320c_range_threshold = 17;
341 } else {
342 ctrl->tCK = TCK_400MHZ;
343 ctrl->edge_offset[0] = 6;
344 ctrl->edge_offset[1] = 2;
345 ctrl->edge_offset[2] = 2;
346 ctrl->timC_offset[0] = 6;
347 ctrl->timC_offset[1] = 2;
348 ctrl->timC_offset[2] = 2;
349 ctrl->reg_320c_range_threshold = 17;
350 }
351
352 /* Initial phase between CLK/CMD pins */
353 ctrl->reg_c14_offset = (256000 / ctrl->tCK) / 66;
354
355 /* DLL_CONFIG_MDLL_W_TIMER */
356 ctrl->reg_5064b0 = (128000 / ctrl->tCK) + 3;
357
358 val32 = (1000 << 8) / ctrl->tCK;
359 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
360
361 /* Find CAS latency */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100362 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100363 printk(BIOS_DEBUG, "Minimum CAS latency : %uT\n", val);
364 /* Find lowest supported CAS latency that satisfies the minimum value */
365 while (!((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
366 && (ctrl->cas_supported >> (val - MIN_CAS))) {
367 val++;
368 }
369 /* Is CAS supported */
370 if (!(ctrl->cas_supported & (1 << (val - MIN_CAS)))) {
371 printk(BIOS_ERR, "CAS %uT not supported. ", val);
372 val = MAX_CAS;
373 /* Find highest supported CAS latency */
374 while (!((ctrl->cas_supported >> (val - MIN_CAS)) & 1))
375 val--;
376
377 printk(BIOS_ERR, "Using CAS %uT instead.\n", val);
378 }
379
380 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
381 ctrl->CAS = val;
382 ctrl->CWL = get_CWL(ctrl->tCK);
383 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
384
385 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100386 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100387 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
388
Arthur Heymans50db9c92017-03-23 18:53:38 +0100389 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100390 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
391
392 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100393 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100394 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
395
396 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100397 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100398 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
399
400 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100401 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100402 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
403
404 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100405 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100406 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
407
408 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100409 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100410 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
411
412 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100413 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100414 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
415
416 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100417 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100418 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
419
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100420 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
421 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
422 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
423 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
424 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
425 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
426 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
427 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100428}
429
430static void dram_freq(ramctr_timing * ctrl)
431{
432 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100433 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
434 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100435 ctrl->tCK = TCK_400MHZ;
436 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100437
438 /* TODO: implement 100Mhz refclock */
439 ctrl->base_freq = 133;
440
Patrick Rudolph305035c2016-11-11 18:38:50 +0100441 while (1) {
442 u8 val2;
443 u32 reg1 = 0;
444
445 /* Step 1 - Set target PCU frequency */
446
447 if (ctrl->tCK <= TCK_1066MHZ) {
448 ctrl->tCK = TCK_1066MHZ;
449 } else if (ctrl->tCK <= TCK_933MHZ) {
450 ctrl->tCK = TCK_933MHZ;
451 } else if (ctrl->tCK <= TCK_800MHZ) {
452 ctrl->tCK = TCK_800MHZ;
453 } else if (ctrl->tCK <= TCK_666MHZ) {
454 ctrl->tCK = TCK_666MHZ;
455 } else if (ctrl->tCK <= TCK_533MHZ) {
456 ctrl->tCK = TCK_533MHZ;
457 } else if (ctrl->tCK <= TCK_400MHZ) {
458 ctrl->tCK = TCK_400MHZ;
459 } else {
460 die ("No lock frequency found");
461 }
462
463 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100464 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100465
466 /* The PLL will never lock if the required frequency is
467 * already set. Exit early to prevent a system hang.
468 */
469 reg1 = MCHBAR32(MC_BIOS_DATA);
470 val2 = (u8) reg1;
471 if (val2)
472 return;
473
474 /* Step 2 - Select frequency in the MCU */
475 reg1 = FRQ;
476 reg1 |= 0x80000000; // set running bit
477 MCHBAR32(MC_BIOS_REQ) = reg1;
478 int i=0;
479 printk(BIOS_DEBUG, "PLL busy... ");
480 while (reg1 & 0x80000000) {
481 udelay(10);
482 i++;
483 reg1 = MCHBAR32(MC_BIOS_REQ);
484 }
485 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
486
487 /* Step 3 - Verify lock frequency */
488 reg1 = MCHBAR32(MC_BIOS_DATA);
489 val2 = (u8) reg1;
490 if (val2 >= FRQ) {
491 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
492 (1000 << 8) / ctrl->tCK);
493 return;
494 }
495 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
496 ctrl->tCK++;
497 }
498}
499
500static void dram_ioregs(ramctr_timing * ctrl)
501{
502 u32 reg, comp2;
503
504 int channel;
505
506 // IO clock
507 FOR_ALL_CHANNELS {
508 MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel];
509 }
510
511 // IO command
512 FOR_ALL_CHANNELS {
513 MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel];
514 }
515
516 // IO control
517 FOR_ALL_POPULATED_CHANNELS {
518 program_timings(ctrl, channel);
519 }
520
521 // Rcomp
522 printram("RCOMP...");
523 reg = 0;
524 while (reg == 0) {
525 reg = MCHBAR32(0x5084) & 0x10000;
526 }
527 printram("done\n");
528
529 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100530 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100531 MCHBAR32(0x3714) = comp2;
532 printram("COMP2 done\n");
533
534 // Set comp1
535 FOR_ALL_POPULATED_CHANNELS {
536 reg = MCHBAR32(0x1810 + channel * 0x100); //ch0
537 reg = (reg & ~0xe00) | (1 << 9); //odt
538 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
539 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
540 MCHBAR32(0x1810 + channel * 0x100) = reg;
541 }
542 printram("COMP1 done\n");
543
544 printram("FORCE RCOMP and wait 20us...");
545 MCHBAR32(0x5f08) |= 0x100;
546 udelay(20);
547 printram("done\n");
548}
549
550int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
551 int s3_resume, int me_uma_size)
552{
553 int err;
554
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100555 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
556 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100557
558 if (!fast_boot) {
559 /* Find fastest common supported parameters */
560 dram_find_common_params(ctrl);
561
562 dram_dimm_mapping(ctrl);
563 }
564
565 /* Set MCU frequency */
566 dram_freq(ctrl);
567
568 if (!fast_boot) {
569 /* Calculate timings */
570 dram_timing(ctrl);
571 }
572
573 /* Set version register */
574 MCHBAR32(0x5034) = 0xC04EB002;
575
576 /* Enable crossover */
577 dram_xover(ctrl);
578
579 /* Set timing and refresh registers */
580 dram_timing_regs(ctrl);
581
582 /* Power mode preset */
583 MCHBAR32(0x4e80) = 0x5500;
584
585 /* Set scheduler parameters */
586 MCHBAR32(0x4c20) = 0x10100005;
587
588 /* Set CPU specific register */
589 set_4f8c();
590
591 /* Clear IO reset bit */
592 MCHBAR32(0x5030) &= ~0x20;
593
594 /* Set MAD-DIMM registers */
595 dram_dimm_set_mapping(ctrl);
596 printk(BIOS_DEBUG, "Done dimm mapping\n");
597
598 /* Zone config */
599 dram_zones(ctrl, 1);
600
601 /* Set memory map */
602 dram_memorymap(ctrl, me_uma_size);
603 printk(BIOS_DEBUG, "Done memory map\n");
604
605 /* Set IO registers */
606 dram_ioregs(ctrl);
607 printk(BIOS_DEBUG, "Done io registers\n");
608
609 udelay(1);
610
611 if (fast_boot) {
612 restore_timings(ctrl);
613 } else {
614 /* Do jedec ddr3 reset sequence */
615 dram_jedecreset(ctrl);
616 printk(BIOS_DEBUG, "Done jedec reset\n");
617
618 /* MRS commands */
619 dram_mrscommands(ctrl);
620 printk(BIOS_DEBUG, "Done MRS commands\n");
621
622 /* Prepare for memory training */
623 prepare_training(ctrl);
624
625 err = read_training(ctrl);
626 if (err)
627 return err;
628
629 err = write_training(ctrl);
630 if (err)
631 return err;
632
633 printram("CP5a\n");
634
635 err = discover_edges(ctrl);
636 if (err)
637 return err;
638
639 printram("CP5b\n");
640
641 err = command_training(ctrl);
642 if (err)
643 return err;
644
645 printram("CP5c\n");
646
647 err = discover_edges_write(ctrl);
648 if (err)
649 return err;
650
651 err = discover_timC_write(ctrl);
652 if (err)
653 return err;
654
655 normalize_training(ctrl);
656 }
657
658 set_4008c(ctrl);
659
660 write_controller_mr(ctrl);
661
662 if (!s3_resume) {
663 err = channel_test(ctrl);
664 if (err)
665 return err;
666 }
667
668 return 0;
669}