blob: 675ac7181c35c61f180727eeee37c0507c3f93c5 [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
Patrick Rudolph305035c2016-11-11 18:38:50 +0100482 ctrl->CWL = get_CWL(ctrl->tCK);
483 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
484
485 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100486 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100487 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
488
Arthur Heymans50db9c92017-03-23 18:53:38 +0100489 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100490 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
491
492 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100493 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100494 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
495
496 /* Find tWR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100497 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100498 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
499
500 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100501 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100502 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
503
504 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100505 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100506 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
507
508 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100509 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100510 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
511
512 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100513 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100514 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
515
516 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100517 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100518 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
519
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100520 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
521 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
522 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
523 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
524 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
525 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
526 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
527 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100528}
529
530static void dram_freq(ramctr_timing * ctrl)
531{
532 if (ctrl->tCK > TCK_400MHZ) {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100533 printk (BIOS_ERR, "DRAM frequency is under lowest supported "
534 "frequency (400 MHz). Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100535 ctrl->tCK = TCK_400MHZ;
536 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100537
Patrick Rudolph305035c2016-11-11 18:38:50 +0100538 while (1) {
539 u8 val2;
540 u32 reg1 = 0;
541
542 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200543 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100544
Patrick Rudolph305035c2016-11-11 18:38:50 +0100545 /* Frequency multiplier. */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100546 u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100547
548 /* The PLL will never lock if the required frequency is
549 * already set. Exit early to prevent a system hang.
550 */
551 reg1 = MCHBAR32(MC_BIOS_DATA);
552 val2 = (u8) reg1;
553 if (val2)
554 return;
555
556 /* Step 2 - Select frequency in the MCU */
557 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100558 if (ctrl->base_freq == 100)
559 reg1 |= 0x100; /* Enable 100Mhz REF clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100560 reg1 |= 0x80000000; // set running bit
561 MCHBAR32(MC_BIOS_REQ) = reg1;
562 int i=0;
563 printk(BIOS_DEBUG, "PLL busy... ");
564 while (reg1 & 0x80000000) {
565 udelay(10);
566 i++;
567 reg1 = MCHBAR32(MC_BIOS_REQ);
568 }
569 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
570
571 /* Step 3 - Verify lock frequency */
572 reg1 = MCHBAR32(MC_BIOS_DATA);
573 val2 = (u8) reg1;
574 if (val2 >= FRQ) {
575 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
576 (1000 << 8) / ctrl->tCK);
577 return;
578 }
579 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
580 ctrl->tCK++;
581 }
582}
583
584static void dram_ioregs(ramctr_timing * ctrl)
585{
586 u32 reg, comp2;
587
588 int channel;
589
590 // IO clock
591 FOR_ALL_CHANNELS {
592 MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel];
593 }
594
595 // IO command
596 FOR_ALL_CHANNELS {
597 MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel];
598 }
599
600 // IO control
601 FOR_ALL_POPULATED_CHANNELS {
602 program_timings(ctrl, channel);
603 }
604
605 // Rcomp
606 printram("RCOMP...");
607 reg = 0;
608 while (reg == 0) {
609 reg = MCHBAR32(0x5084) & 0x10000;
610 }
611 printram("done\n");
612
613 // Set comp2
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100614 comp2 = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100615 MCHBAR32(0x3714) = comp2;
616 printram("COMP2 done\n");
617
618 // Set comp1
619 FOR_ALL_POPULATED_CHANNELS {
620 reg = MCHBAR32(0x1810 + channel * 0x100); //ch0
621 reg = (reg & ~0xe00) | (1 << 9); //odt
622 reg = (reg & ~0xe00000) | (1 << 21); //clk drive up
623 reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up
624 MCHBAR32(0x1810 + channel * 0x100) = reg;
625 }
626 printram("COMP1 done\n");
627
628 printram("FORCE RCOMP and wait 20us...");
629 MCHBAR32(0x5f08) |= 0x100;
630 udelay(20);
631 printram("done\n");
632}
633
634int try_init_dram_ddr3_ivy(ramctr_timing *ctrl, int fast_boot,
635 int s3_resume, int me_uma_size)
636{
637 int err;
638
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100639 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n",
640 fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100641
642 if (!fast_boot) {
643 /* Find fastest common supported parameters */
644 dram_find_common_params(ctrl);
645
646 dram_dimm_mapping(ctrl);
647 }
648
649 /* Set MCU frequency */
650 dram_freq(ctrl);
651
652 if (!fast_boot) {
653 /* Calculate timings */
654 dram_timing(ctrl);
655 }
656
657 /* Set version register */
658 MCHBAR32(0x5034) = 0xC04EB002;
659
660 /* Enable crossover */
661 dram_xover(ctrl);
662
663 /* Set timing and refresh registers */
664 dram_timing_regs(ctrl);
665
666 /* Power mode preset */
667 MCHBAR32(0x4e80) = 0x5500;
668
669 /* Set scheduler parameters */
670 MCHBAR32(0x4c20) = 0x10100005;
671
672 /* Set CPU specific register */
673 set_4f8c();
674
675 /* Clear IO reset bit */
676 MCHBAR32(0x5030) &= ~0x20;
677
678 /* Set MAD-DIMM registers */
679 dram_dimm_set_mapping(ctrl);
680 printk(BIOS_DEBUG, "Done dimm mapping\n");
681
682 /* Zone config */
683 dram_zones(ctrl, 1);
684
685 /* Set memory map */
686 dram_memorymap(ctrl, me_uma_size);
687 printk(BIOS_DEBUG, "Done memory map\n");
688
689 /* Set IO registers */
690 dram_ioregs(ctrl);
691 printk(BIOS_DEBUG, "Done io registers\n");
692
693 udelay(1);
694
695 if (fast_boot) {
696 restore_timings(ctrl);
697 } else {
698 /* Do jedec ddr3 reset sequence */
699 dram_jedecreset(ctrl);
700 printk(BIOS_DEBUG, "Done jedec reset\n");
701
702 /* MRS commands */
703 dram_mrscommands(ctrl);
704 printk(BIOS_DEBUG, "Done MRS commands\n");
705
706 /* Prepare for memory training */
707 prepare_training(ctrl);
708
709 err = read_training(ctrl);
710 if (err)
711 return err;
712
713 err = write_training(ctrl);
714 if (err)
715 return err;
716
717 printram("CP5a\n");
718
719 err = discover_edges(ctrl);
720 if (err)
721 return err;
722
723 printram("CP5b\n");
724
725 err = command_training(ctrl);
726 if (err)
727 return err;
728
729 printram("CP5c\n");
730
731 err = discover_edges_write(ctrl);
732 if (err)
733 return err;
734
735 err = discover_timC_write(ctrl);
736 if (err)
737 return err;
738
739 normalize_training(ctrl);
740 }
741
742 set_4008c(ctrl);
743
744 write_controller_mr(ctrl);
745
746 if (!s3_resume) {
747 err = channel_test(ctrl);
748 if (err)
749 return err;
750 }
751
752 return 0;
753}