blob: 19dea2f2e182ddf72379051d9a9eacb1ad9ed6c6 [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>
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +010022#include <arch/io.h>
23#include <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010024#include "raminit_native.h"
25#include "raminit_common.h"
26
27/* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010028static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010029{
30 u32 FRQ;
Patrick Rudolph77eaba32016-11-11 18:55:54 +010031
32 FRQ = 256000 / (tCK * base_freq);
33
34 if (base_freq == 100) {
35 if (FRQ > 12)
36 return 12;
37 if (FRQ < 7)
38 return 7;
39 } else {
40 if (FRQ > 10)
41 return 10;
42 if (FRQ < 3)
43 return 3;
44 }
45
Patrick Rudolph305035c2016-11-11 18:38:50 +010046 return FRQ;
47}
48
Patrick Rudolph77eaba32016-11-11 18:55:54 +010049static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010050{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010051 u32 refi;
52
53 if (base_freq == 100) {
54 /* Get REFI based on MCU frequency using the following rule:
55 * tREFI = 7.8usec
56 * _________________________________________
57 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
58 * REFI : | 5460 | 6240 | 7020 | 7800 | 8580 | 9360 |
59 */
60 static const u32 frq_xs_map[] =
61 { 5460, 6240, 7020, 7800, 8580, 9360 };
62 refi = frq_xs_map[get_FRQ(tCK, 100) - 7];
63 } else {
64 /* Get REFI based on MCU frequency using the following rule:
65 * tREFI = 7.8usec
66 * ________________________________________________________
67 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
68 * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | 9360 | 10400 |
69 */
70 static const u32 frq_refi_map[] =
71 { 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400 };
72 refi = frq_refi_map[get_FRQ(tCK, 133) - 3];
73 }
74
75 return refi;
Patrick Rudolph305035c2016-11-11 18:38:50 +010076}
77
Patrick Rudolph77eaba32016-11-11 18:55:54 +010078static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010079{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010080 u8 xsoffset;
81
82 if (base_freq == 100) {
83 /* Get XSOffset based on MCU frequency using the following rule:
84 * tXS-offset: tXS = tRFC+10ns.
85 * _____________________________
86 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
87 * XSOffset : | 7 | 8 | 9 | 10 | 11 | 12 |
88 */
89 static const u8 frq_xs_map[] = { 7, 8, 9, 10, 11, 12 };
90 xsoffset = frq_xs_map[get_FRQ(tCK, 100) - 7];
91 } else {
92 /* Get XSOffset based on MCU frequency using the following rule:
93 * ___________________________________
94 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
95 * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 14 |
96 */
97 static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11, 12, 14 };
98 xsoffset = frq_xs_map[get_FRQ(tCK, 133) - 3];
99 }
100
101 return xsoffset;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100102}
103
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100104static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100105{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100106 u8 mod;
107
108 if (base_freq == 100) {
109 /* Get MOD based on MCU frequency using the following rule:
110 * _____________________________
111 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
112 * MOD : | 12 | 12 | 14 | 15 | 17 | 18 |
113 */
114
115 static const u8 frq_mod_map[] = { 12, 12, 14, 15, 17, 18 };
116 mod = frq_mod_map[get_FRQ(tCK, 100) - 7];
117 } else {
118 /* Get MOD based on MCU frequency using the following rule:
119 * _______________________________________
120 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
121 * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | 18 | 20 |
122 */
123
124 static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16, 18, 20 };
125 mod = frq_mod_map[get_FRQ(tCK, 133) - 3];
126 }
127 return mod;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100128}
129
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100130static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100131{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100132 u8 wlo;
133
134 if (base_freq == 100) {
135 /* Get WLO based on MCU frequency using the following rule:
136 * Write leveling output delay
137 * _____________________________
138 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
139 * MOD : | 6 | 6 | 7 | 8 | 9 | 9 |
140 */
141
142 static const u8 frq_wlo_map[] = { 6, 6, 7, 8, 9, 9 };
143 wlo = frq_wlo_map[get_FRQ(tCK, 100) - 7];
144 } else {
145 /* Get WLO based on MCU frequency using the following rule:
146 * Write leveling output delay
147 * ________________________________
148 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
149 * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | 9 | 10 |
150 */
151 static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8, 9, 10 };
152 wlo = frq_wlo_map[get_FRQ(tCK, 133) - 3];
153 }
154
155 return wlo;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100156}
157
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100158static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100159{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100160 u8 cke;
161
162 if (base_freq == 100) {
163 /* Get CKE based on MCU frequency using the following rule:
164 * _____________________________
165 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
166 * MOD : | 4 | 4 | 5 | 5 | 6 | 6 |
167 */
168
169 static const u8 frq_cke_map[] = { 4, 4, 5, 5, 6, 6 };
170 cke = frq_cke_map[get_FRQ(tCK, 100) - 7];
171 } else {
172 /* Get CKE based on MCU frequency using the following rule:
173 * ________________________________
174 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
175 * WLO : | 3 | 3 | 4 | 4 | 5 | 6 | 6 | 7 |
176 */
177 static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6, 6, 7 };
178 cke = frq_cke_map[get_FRQ(tCK, 133) - 3];
179 }
180
181 return cke;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100182}
183
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100184static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100185{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100186 u8 xpdll;
187
188 if (base_freq == 100) {
189 /* Get XPDLL based on MCU frequency using the following rule:
190 * _____________________________
191 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
192 * XPDLL : | 17 | 20 | 22 | 24 | 27 | 32 |
193 */
194
195 static const u8 frq_xpdll_map[] = { 17, 20, 22, 24, 27, 32 };
196 xpdll = frq_xpdll_map[get_FRQ(tCK, 100) - 7];
197 } else {
198 /* Get XPDLL based on MCU frequency using the following rule:
199 * _______________________________________
200 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
201 * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | 29 | 32 |
202 */
203 static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26, 29, 32 };
204 xpdll = frq_xpdll_map[get_FRQ(tCK, 133) - 3];
205 }
206
207 return xpdll;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100208}
209
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100210static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100211{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100212 u8 xp;
213
214 if (base_freq == 100) {
215 /* Get XP based on MCU frequency using the following rule:
216 * _____________________________
217 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
218 * XP : | 5 | 5 | 6 | 6 | 7 | 8 |
219 */
220
221 static const u8 frq_xp_map[] = { 5, 5, 6, 6, 7, 8 };
222 xp = frq_xp_map[get_FRQ(tCK, 100) - 7];
223 } else {
224 /* Get XP based on MCU frequency using the following rule:
225 * _______________________________________
226 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
227 * XP : | 3 | 4 | 4 | 5 | 6 | 7 | 8 | 8 |
228 */
229 static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 , 8, 8 };
230 xp = frq_xp_map[get_FRQ(tCK, 133) - 3];
231 }
232
233 return xp;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100234}
235
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100236static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100237{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100238 u8 aonpd;
239
240 if (base_freq == 100) {
241 /* Get AONPD based on MCU frequency using the following rule:
242 * _____________________________
243 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
244 * AONPD : | 6 | 8 | 8 | 9 | 10 | 11 |
245 */
246
247 static const u8 frq_aonpd_map[] = { 6, 8, 8, 9, 10, 11 };
248 aonpd = frq_aonpd_map[get_FRQ(tCK, 100) - 7];
249 } else {
250 /* Get AONPD based on MCU frequency using the following rule:
251 * _______________________________________
252 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
253 * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | 11 | 12 |
254 */
255 static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10, 11, 12 };
256 aonpd = frq_aonpd_map[get_FRQ(tCK, 133) - 3];
257 }
258
259 return aonpd;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100260}
261
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100262static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100263{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100264 u32 comp2;
265
266 if (base_freq == 100) {
267 /* Get COMP2 based on MCU frequency using the following rule:
268 * ______________________________________________________________
269 * FRQ : | 7 | 8 | 9 | 10 | 11 | 12 |
270 * COMP : | CA8C264 | C6671E4 | C6671E4 | C446964 | C235924 | C235924 |
271 */
272
273 static const u32 frq_comp2_map[] = { 0xCA8C264, 0xC6671E4, 0xC6671E4, 0xC446964, 0xC235924, 0xC235924 };
274 comp2 = frq_comp2_map[get_FRQ(tCK, 100) - 7];
275 } else {
276 /* Get COMP2 based on MCU frequency using the following rule:
277 * ________________________________________________________________________________
278 * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
279 * COMP : | D6FF5E4 | CEBDB64 | CA8C264 | C6671E4 | C446964 | C235924 | C235924 | C235924 |
280 */
281 static const u32 frq_comp2_map[] = { 0xD6FF5E4, 0xCEBDB64, 0xCA8C264,
282 0xC6671E4, 0xC446964, 0xC235924, 0xC235924, 0xC235924
283 };
284 comp2 = frq_comp2_map[get_FRQ(tCK, 133) - 3];
285 }
286
287 return comp2;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100288}
289
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200290static void ivb_normalize_tclk(ramctr_timing *ctrl,
291 bool ref_100mhz_support)
292{
293 if (ctrl->tCK <= TCK_1200MHZ) {
294 ctrl->tCK = TCK_1200MHZ;
295 ctrl->base_freq = 100;
296 } else if (ctrl->tCK <= TCK_1100MHZ) {
297 ctrl->tCK = TCK_1100MHZ;
298 ctrl->base_freq = 100;
299 } else if (ctrl->tCK <= TCK_1066MHZ) {
300 ctrl->tCK = TCK_1066MHZ;
301 ctrl->base_freq = 133;
302 } else if (ctrl->tCK <= TCK_1000MHZ) {
303 ctrl->tCK = TCK_1000MHZ;
304 ctrl->base_freq = 100;
305 } else if (ctrl->tCK <= TCK_933MHZ) {
306 ctrl->tCK = TCK_933MHZ;
307 ctrl->base_freq = 133;
308 } else if (ctrl->tCK <= TCK_900MHZ) {
309 ctrl->tCK = TCK_900MHZ;
310 ctrl->base_freq = 100;
311 } else if (ctrl->tCK <= TCK_800MHZ) {
312 ctrl->tCK = TCK_800MHZ;
313 ctrl->base_freq = 133;
314 } else if (ctrl->tCK <= TCK_700MHZ) {
315 ctrl->tCK = TCK_700MHZ;
316 ctrl->base_freq = 100;
317 } else if (ctrl->tCK <= TCK_666MHZ) {
318 ctrl->tCK = TCK_666MHZ;
319 ctrl->base_freq = 133;
320 } else if (ctrl->tCK <= TCK_533MHZ) {
321 ctrl->tCK = TCK_533MHZ;
322 ctrl->base_freq = 133;
323 } else if (ctrl->tCK <= TCK_400MHZ) {
324 ctrl->tCK = TCK_400MHZ;
325 ctrl->base_freq = 133;
326 } else {
327 ctrl->tCK = 0;
328 return;
329 }
330
331 if (!ref_100mhz_support && ctrl->base_freq == 100) {
332 /* Skip unsupported frequency. */
333 ctrl->tCK++;
334 ivb_normalize_tclk(ctrl, ref_100mhz_support);
335 }
336}
337
338static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100339{
340 u8 val;
341 u32 val32;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200342 u32 reg32;
343 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100344
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200345 /* 100 Mhz reference clock supported */
346 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
347 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
348 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n",
349 ref_100mhz_support ? "yes" : "no");
350
351 /* Find CAS latency */
352 while (1) {
353 /* Normalising tCK before computing clock could potentially
354 * results in lower selected CAS, which is desired.
355 */
356 ivb_normalize_tclk(ctrl, ref_100mhz_support);
357 if (!(ctrl->tCK))
358 die("Couldn't find compatible clock / CAS settings\n");
359 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
360 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
361 for (; val <= MAX_CAS; val++)
362 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
363 break;
364 if (val == (MAX_CAS + 1)) {
365 ctrl->tCK++;
366 continue;
367 } else {
368 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
369 break;
370 }
371 }
372
373 val32 = NS2MHZ_DIV256 / ctrl->tCK;
374 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32);
375
376 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
377 ctrl->CAS = val;
378}
379
380
381static void dram_timing(ramctr_timing *ctrl)
382{
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100383 /* Maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
384 * We cap it at 1200Mhz (DDR3 2400).
Patrick Rudolph305035c2016-11-11 18:38:50 +0100385 * Then, align it to the closest JEDEC standard frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200386 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100387 ctrl->edge_offset[0] = 18; //XXX: guessed
388 ctrl->edge_offset[1] = 8;
389 ctrl->edge_offset[2] = 8;
390 ctrl->timC_offset[0] = 20; //XXX: guessed
391 ctrl->timC_offset[1] = 8;
392 ctrl->timC_offset[2] = 8;
393 ctrl->reg_320c_range_threshold = 10;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200394 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100395 ctrl->edge_offset[0] = 17; //XXX: guessed
396 ctrl->edge_offset[1] = 7;
397 ctrl->edge_offset[2] = 7;
398 ctrl->timC_offset[0] = 19; //XXX: guessed
399 ctrl->timC_offset[1] = 7;
400 ctrl->timC_offset[2] = 7;
401 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200402 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100403 ctrl->edge_offset[0] = 16;
404 ctrl->edge_offset[1] = 7;
405 ctrl->edge_offset[2] = 7;
406 ctrl->timC_offset[0] = 18;
407 ctrl->timC_offset[1] = 7;
408 ctrl->timC_offset[2] = 7;
409 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200410 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100411 ctrl->edge_offset[0] = 15; //XXX: guessed
412 ctrl->edge_offset[1] = 6;
413 ctrl->edge_offset[2] = 6;
414 ctrl->timC_offset[0] = 17; //XXX: guessed
415 ctrl->timC_offset[1] = 6;
416 ctrl->timC_offset[2] = 6;
417 ctrl->reg_320c_range_threshold = 13;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200418 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100419 ctrl->edge_offset[0] = 14;
420 ctrl->edge_offset[1] = 6;
421 ctrl->edge_offset[2] = 6;
422 ctrl->timC_offset[0] = 15;
423 ctrl->timC_offset[1] = 6;
424 ctrl->timC_offset[2] = 6;
425 ctrl->reg_320c_range_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200426 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100427 ctrl->edge_offset[0] = 14; //XXX: guessed
428 ctrl->edge_offset[1] = 6;
429 ctrl->edge_offset[2] = 6;
430 ctrl->timC_offset[0] = 15; //XXX: guessed
431 ctrl->timC_offset[1] = 6;
432 ctrl->timC_offset[2] = 6;
433 ctrl->reg_320c_range_threshold = 12;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200434 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100435 ctrl->edge_offset[0] = 13;
436 ctrl->edge_offset[1] = 5;
437 ctrl->edge_offset[2] = 5;
438 ctrl->timC_offset[0] = 14;
439 ctrl->timC_offset[1] = 5;
440 ctrl->timC_offset[2] = 5;
441 ctrl->reg_320c_range_threshold = 15;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200442 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100443 ctrl->edge_offset[0] = 13; //XXX: guessed
444 ctrl->edge_offset[1] = 5;
445 ctrl->edge_offset[2] = 5;
446 ctrl->timC_offset[0] = 14; //XXX: guessed
447 ctrl->timC_offset[1] = 5;
448 ctrl->timC_offset[2] = 5;
449 ctrl->reg_320c_range_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200450 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100451 ctrl->edge_offset[0] = 10;
452 ctrl->edge_offset[1] = 4;
453 ctrl->edge_offset[2] = 4;
454 ctrl->timC_offset[0] = 11;
455 ctrl->timC_offset[1] = 4;
456 ctrl->timC_offset[2] = 4;
457 ctrl->reg_320c_range_threshold = 16;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200458 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100459 ctrl->edge_offset[0] = 8;
460 ctrl->edge_offset[1] = 3;
461 ctrl->edge_offset[2] = 3;
462 ctrl->timC_offset[0] = 9;
463 ctrl->timC_offset[1] = 3;
464 ctrl->timC_offset[2] = 3;
465 ctrl->reg_320c_range_threshold = 17;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200466 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100467 ctrl->edge_offset[0] = 6;
468 ctrl->edge_offset[1] = 2;
469 ctrl->edge_offset[2] = 2;
470 ctrl->timC_offset[0] = 6;
471 ctrl->timC_offset[1] = 2;
472 ctrl->timC_offset[2] = 2;
473 ctrl->reg_320c_range_threshold = 17;
474 }
475
476 /* Initial phase between CLK/CMD pins */
477 ctrl->reg_c14_offset = (256000 / ctrl->tCK) / 66;
478
479 /* DLL_CONFIG_MDLL_W_TIMER */
480 ctrl->reg_5064b0 = (128000 / ctrl->tCK) + 3;
481
Dan Elkoubydabebc32018-04-13 18:47:10 +0300482 if (ctrl->tCWL)
483 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
484 else
485 ctrl->CWL = get_CWL(ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100486 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
487
488 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100489 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100490 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
491
Arthur Heymans50db9c92017-03-23 18:53:38 +0100492 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100493 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
494
495 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100496 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100497 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
498
499 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100500 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100501 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
502
503 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100504 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100505 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
506
507 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100508 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100509 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
510
511 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100512 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100513 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
514
515 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100516 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100517 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
518
519 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100520 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100521 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
522
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100523 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
524 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
525 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
526 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
527 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
528 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
529 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
530 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100531}
532
533static void dram_freq(ramctr_timing * ctrl)
534{
535 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100536 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
537 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100538 ctrl->tCK = TCK_400MHZ;
539 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100540
Patrick Rudolph305035c2016-11-11 18:38:50 +0100541 while (1) {
542 u8 val2;
543 u32 reg1 = 0;
544
545 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200546 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100547
Patrick Rudolph305035c2016-11-11 18:38:50 +0100548 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100549 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100550
551 /* The PLL will never lock if the required frequency is
552 * already set. Exit early to prevent a system hang.
553 */
554 reg1 = MCHBAR32(MC_BIOS_DATA);
555 val2 = (u8) reg1;
556 if (val2)
557 return;
558
559 /* Step 2 - Select frequency in the MCU */
560 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100561 if (ctrl->base_freq == 100)
562 reg1 |= 0x100; /* Enable 100Mhz REF clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100563 reg1 |= 0x80000000; // set running bit
564 MCHBAR32(MC_BIOS_REQ) = reg1;
565 int i=0;
566 printk(BIOS_DEBUG, "PLL busy... ");
567 while (reg1 & 0x80000000) {
568 udelay(10);
569 i++;
570 reg1 = MCHBAR32(MC_BIOS_REQ);
571 }
572 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
573
574 /* Step 3 - Verify lock frequency */
575 reg1 = MCHBAR32(MC_BIOS_DATA);
576 val2 = (u8) reg1;
577 if (val2 >= FRQ) {
578 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
579 (1000 << 8) / ctrl->tCK);
580 return;
581 }
582 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
583 ctrl->tCK++;
584 }
585}
586
587static void dram_ioregs(ramctr_timing * ctrl)
588{
589 u32 reg, comp2;
590
591 int channel;
592
593 // IO clock
594 FOR_ALL_CHANNELS {
595 MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel];
596 }
597
598 // IO command
599 FOR_ALL_CHANNELS {
600 MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel];
601 }
602
603 // IO control
604 FOR_ALL_POPULATED_CHANNELS {
605 program_timings(ctrl, channel);
606 }
607
608 // Rcomp
609 printram("RCOMP...");
610 reg = 0;
611 while (reg == 0) {
612 reg = MCHBAR32(0x5084) & 0x10000;
613 }
614 printram("done\n");
615
616 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100617 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100618 MCHBAR32(0x3714) = comp2;
619 printram("COMP2 done\n");
620
621 // Set comp1
622 FOR_ALL_POPULATED_CHANNELS {
623 reg = MCHBAR32(0x1810 + channel * 0x100); //ch0
624 reg = (reg & ~0xe00) | (1 << 9); //odt
625 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
626 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
627 MCHBAR32(0x1810 + channel * 0x100) = reg;
628 }
629 printram("COMP1 done\n");
630
631 printram("FORCE RCOMP and wait 20us...");
632 MCHBAR32(0x5f08) |= 0x100;
633 udelay(20);
634 printram("done\n");
635}
636
637int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
638 int s3_resume, int me_uma_size)
639{
640 int err;
641
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100642 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
643 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100644
645 if (!fast_boot) {
646 /* Find fastest common supported parameters */
647 dram_find_common_params(ctrl);
648
649 dram_dimm_mapping(ctrl);
650 }
651
652 /* Set MCU frequency */
653 dram_freq(ctrl);
654
655 if (!fast_boot) {
656 /* Calculate timings */
657 dram_timing(ctrl);
658 }
659
660 /* Set version register */
661 MCHBAR32(0x5034) = 0xC04EB002;
662
663 /* Enable crossover */
664 dram_xover(ctrl);
665
666 /* Set timing and refresh registers */
667 dram_timing_regs(ctrl);
668
669 /* Power mode preset */
670 MCHBAR32(0x4e80) = 0x5500;
671
672 /* Set scheduler parameters */
673 MCHBAR32(0x4c20) = 0x10100005;
674
675 /* Set CPU specific register */
676 set_4f8c();
677
678 /* Clear IO reset bit */
679 MCHBAR32(0x5030) &= ~0x20;
680
681 /* Set MAD-DIMM registers */
682 dram_dimm_set_mapping(ctrl);
683 printk(BIOS_DEBUG, "Done dimm mapping\n");
684
685 /* Zone config */
686 dram_zones(ctrl, 1);
687
688 /* Set memory map */
689 dram_memorymap(ctrl, me_uma_size);
690 printk(BIOS_DEBUG, "Done memory map\n");
691
692 /* Set IO registers */
693 dram_ioregs(ctrl);
694 printk(BIOS_DEBUG, "Done io registers\n");
695
696 udelay(1);
697
698 if (fast_boot) {
699 restore_timings(ctrl);
700 } else {
701 /* Do jedec ddr3 reset sequence */
702 dram_jedecreset(ctrl);
703 printk(BIOS_DEBUG, "Done jedec reset\n");
704
705 /* MRS commands */
706 dram_mrscommands(ctrl);
707 printk(BIOS_DEBUG, "Done MRS commands\n");
708
709 /* Prepare for memory training */
710 prepare_training(ctrl);
711
712 err = read_training(ctrl);
713 if (err)
714 return err;
715
716 err = write_training(ctrl);
717 if (err)
718 return err;
719
720 printram("CP5a\n");
721
722 err = discover_edges(ctrl);
723 if (err)
724 return err;
725
726 printram("CP5b\n");
727
728 err = command_training(ctrl);
729 if (err)
730 return err;
731
732 printram("CP5c\n");
733
734 err = discover_edges_write(ctrl);
735 if (err)
736 return err;
737
738 err = discover_timC_write(ctrl);
739 if (err)
740 return err;
741
742 normalize_training(ctrl);
743 }
744
745 set_4008c(ctrl);
746
747 write_controller_mr(ctrl);
748
749 if (!s3_resume) {
750 err = channel_test(ctrl);
751 if (err)
752 return err;
753 }
754
755 return 0;
756}