blob: 06d23825b6364266d883f3fb976e92549ff220c4 [file] [log] [blame]
Patrick Rudolph305035c2016-11-11 18:38:50 +01001/*
2 * This file is part of the coreboot project.
3 *
Patrick Rudolph305035c2016-11-11 18:38:50 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <console/console.h>
16#include <console/usb.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010017#include <delay.h>
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +010018#include <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +010019#include "raminit_native.h"
20#include "raminit_common.h"
21
Angel Pons7c49cb82020-03-16 23:17:32 +010022/* Frequency multiplier */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010023static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010024{
Angel Pons7c49cb82020-03-16 23:17:32 +010025 const u32 FRQ = 256000 / (tCK * base_freq);
Patrick Rudolph77eaba32016-11-11 18:55:54 +010026
27 if (base_freq == 100) {
28 if (FRQ > 12)
29 return 12;
30 if (FRQ < 7)
31 return 7;
32 } else {
33 if (FRQ > 10)
34 return 10;
35 if (FRQ < 3)
36 return 3;
37 }
38
Patrick Rudolph305035c2016-11-11 18:38:50 +010039 return FRQ;
40}
41
Angel Pons7c49cb82020-03-16 23:17:32 +010042/* Get REFI based on MC frequency, tREFI = 7.8usec */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010043static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010044{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010045 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010046 static const u32 frq_xs_map[] = {
47 /* FRQ: 7, 8, 9, 10, 11, 12, */
48 5460, 6240, 7020, 7800, 8580, 9360,
49 };
50 return frq_xs_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010051
Angel Pons7c49cb82020-03-16 23:17:32 +010052 } else {
53 static const u32 frq_refi_map[] = {
54 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
55 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400,
56 };
57 return frq_refi_map[get_FRQ(tCK, 133) - 3];
58 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010059}
60
Angel Pons7c49cb82020-03-16 23:17:32 +010061/* Get XSOffset based on MC frequency, tXS-Offset: tXS = tRFC + 10ns */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010062static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010063{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010064 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010065 static const u8 frq_xs_map[] = {
66 /* FRQ: 7, 8, 9, 10, 11, 12, */
67 7, 8, 9, 10, 11, 12,
68 };
69 return frq_xs_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010070
Angel Pons7c49cb82020-03-16 23:17:32 +010071 } else {
72 static const u8 frq_xs_map[] = {
73 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
74 4, 6, 7, 8, 10, 11, 12, 14,
75 };
76 return frq_xs_map[get_FRQ(tCK, 133) - 3];
77 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010078}
79
Angel Pons7c49cb82020-03-16 23:17:32 +010080/* Get MOD based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010081static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010082{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010083 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010084 static const u8 frq_mod_map[] = {
85 /* FRQ: 7, 8, 9, 10, 11, 12, */
86 12, 12, 14, 15, 17, 18,
87 };
88 return frq_mod_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010089
Patrick Rudolph77eaba32016-11-11 18:55:54 +010090 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +010091 static const u8 frq_mod_map[] = {
92 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
93 12, 12, 12, 12, 15, 16, 18, 20,
94 };
95 return frq_mod_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010096 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010097}
98
Angel Pons7c49cb82020-03-16 23:17:32 +010099/* Get Write Leveling Output delay based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100100static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100101{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100102 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100103 static const u8 frq_wlo_map[] = {
104 /* FRQ: 7, 8, 9, 10, 11, 12, */
105 6, 6, 7, 8, 9, 9,
106 };
107 return frq_wlo_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100108
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100109 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100110 static const u8 frq_wlo_map[] = {
111 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
112 4, 5, 6, 6, 8, 8, 9, 10,
113 };
114 return frq_wlo_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100115 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100116}
117
Angel Pons7c49cb82020-03-16 23:17:32 +0100118/* Get CKE based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100119static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100120{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100121 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100122 static const u8 frq_cke_map[] = {
123 /* FRQ: 7, 8, 9, 10, 11, 12, */
124 4, 4, 5, 5, 6, 6,
125 };
126 return frq_cke_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100127
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100128 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100129 static const u8 frq_cke_map[] = {
130 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
131 3, 3, 4, 4, 5, 6, 6, 7,
132 };
133 return frq_cke_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100134 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100135}
136
Angel Pons7c49cb82020-03-16 23:17:32 +0100137/* Get XPDLL based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100138static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100139{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100140 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100141 static const u8 frq_xpdll_map[] = {
142 /* FRQ: 7, 8, 9, 10, 11, 12, */
143 17, 20, 22, 24, 27, 32,
144 };
145 return frq_xpdll_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100146
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100147 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100148 static const u8 frq_xpdll_map[] = {
149 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
150 10, 13, 16, 20, 23, 26, 29, 32,
151 };
152 return frq_xpdll_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100153 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100154}
155
Angel Pons7c49cb82020-03-16 23:17:32 +0100156/* Get XP based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100157static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100158{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100159 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100160 static const u8 frq_xp_map[] = {
161 /* FRQ: 7, 8, 9, 10, 11, 12, */
162 5, 5, 6, 6, 7, 8,
163 };
164 return frq_xp_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100165 } else {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100166
Angel Pons7c49cb82020-03-16 23:17:32 +0100167 static const u8 frq_xp_map[] = {
168 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
169 3, 4, 4, 5, 6, 7, 8, 8
170 };
171 return frq_xp_map[get_FRQ(tCK, 133) - 3];
172 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100173}
174
Angel Pons7c49cb82020-03-16 23:17:32 +0100175/* Get AONPD based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100176static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100177{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100178 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100179 static const u8 frq_aonpd_map[] = {
180 /* FRQ: 7, 8, 9, 10, 11, 12, */
181 6, 8, 8, 9, 10, 11,
182 };
183 return frq_aonpd_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100184
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100185 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100186 static const u8 frq_aonpd_map[] = {
187 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
188 4, 5, 6, 8, 8, 10, 11, 12,
189 };
190 return frq_aonpd_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100191 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100192}
193
Angel Pons7c49cb82020-03-16 23:17:32 +0100194/* Get COMP2 based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100195static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100196{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100197 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100198 static const u32 frq_comp2_map[] = {
199 // FRQ: 7, 8, 9, 10, 11, 12,
200 0x0CA8C264, 0x0C6671E4, 0x0C6671E4, 0x0C446964, 0x0C235924, 0x0C235924,
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100201 };
Angel Pons7c49cb82020-03-16 23:17:32 +0100202 return frq_comp2_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100203
Angel Pons7c49cb82020-03-16 23:17:32 +0100204 } else {
205 static const u32 frq_comp2_map[] = {
206 /* FRQ: 3, 4, 5, 6, */
207 0x0D6FF5E4, 0x0CEBDB64, 0x0CA8C264, 0x0C6671E4,
208
209 /* FRQ: 7, 8, 9, 10, */
210 0x0C446964, 0x0C235924, 0x0C235924, 0x0C235924,
211 };
212 return frq_comp2_map[get_FRQ(tCK, 133) - 3];
213 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100214}
215
Angel Pons7c49cb82020-03-16 23:17:32 +0100216static void ivb_normalize_tclk(ramctr_timing *ctrl, bool ref_100mhz_support)
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200217{
218 if (ctrl->tCK <= TCK_1200MHZ) {
219 ctrl->tCK = TCK_1200MHZ;
220 ctrl->base_freq = 100;
221 } else if (ctrl->tCK <= TCK_1100MHZ) {
222 ctrl->tCK = TCK_1100MHZ;
223 ctrl->base_freq = 100;
224 } else if (ctrl->tCK <= TCK_1066MHZ) {
225 ctrl->tCK = TCK_1066MHZ;
226 ctrl->base_freq = 133;
227 } else if (ctrl->tCK <= TCK_1000MHZ) {
228 ctrl->tCK = TCK_1000MHZ;
229 ctrl->base_freq = 100;
230 } else if (ctrl->tCK <= TCK_933MHZ) {
231 ctrl->tCK = TCK_933MHZ;
232 ctrl->base_freq = 133;
233 } else if (ctrl->tCK <= TCK_900MHZ) {
234 ctrl->tCK = TCK_900MHZ;
235 ctrl->base_freq = 100;
236 } else if (ctrl->tCK <= TCK_800MHZ) {
237 ctrl->tCK = TCK_800MHZ;
238 ctrl->base_freq = 133;
239 } else if (ctrl->tCK <= TCK_700MHZ) {
240 ctrl->tCK = TCK_700MHZ;
241 ctrl->base_freq = 100;
242 } else if (ctrl->tCK <= TCK_666MHZ) {
243 ctrl->tCK = TCK_666MHZ;
244 ctrl->base_freq = 133;
245 } else if (ctrl->tCK <= TCK_533MHZ) {
246 ctrl->tCK = TCK_533MHZ;
247 ctrl->base_freq = 133;
248 } else if (ctrl->tCK <= TCK_400MHZ) {
249 ctrl->tCK = TCK_400MHZ;
250 ctrl->base_freq = 133;
251 } else {
252 ctrl->tCK = 0;
253 return;
254 }
255
256 if (!ref_100mhz_support && ctrl->base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100257 /* Skip unsupported frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200258 ctrl->tCK++;
259 ivb_normalize_tclk(ctrl, ref_100mhz_support);
260 }
261}
262
263static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100264{
265 u8 val;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200266 u32 reg32;
267 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100268
Angel Pons7c49cb82020-03-16 23:17:32 +0100269 /* 100 MHz reference clock supported */
270 reg32 = pci_read_config32(HOST_BRIDGE, CAPID0_B);
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200271 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
Angel Pons7c49cb82020-03-16 23:17:32 +0100272 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n", ref_100mhz_support ? "yes"
273 : "no");
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200274
275 /* Find CAS latency */
276 while (1) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100277 /*
278 * Normalising tCK before computing clock could potentially
279 * result in a lower selected CAS, which is desired.
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200280 */
281 ivb_normalize_tclk(ctrl, ref_100mhz_support);
282 if (!(ctrl->tCK))
283 die("Couldn't find compatible clock / CAS settings\n");
Angel Pons7c49cb82020-03-16 23:17:32 +0100284
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200285 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
286 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
287 for (; val <= MAX_CAS; val++)
288 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
289 break;
Angel Pons7c49cb82020-03-16 23:17:32 +0100290
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200291 if (val == (MAX_CAS + 1)) {
292 ctrl->tCK++;
293 continue;
294 } else {
295 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
296 break;
297 }
298 }
299
Angel Pons7c49cb82020-03-16 23:17:32 +0100300 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", NS2MHZ_DIV256 / ctrl->tCK);
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200301 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
302 ctrl->CAS = val;
303}
304
305
306static void dram_timing(ramctr_timing *ctrl)
307{
Angel Pons7c49cb82020-03-16 23:17:32 +0100308 /*
309 * On Ivy Bridge, the maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
310 * Cap it at 1200MHz (DDR3 2400), and align it to the closest JEDEC standard frequency.
311 */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200312 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100313 ctrl->edge_offset[0] = 18; //XXX: guessed
314 ctrl->edge_offset[1] = 8;
315 ctrl->edge_offset[2] = 8;
316 ctrl->timC_offset[0] = 20; //XXX: guessed
317 ctrl->timC_offset[1] = 8;
318 ctrl->timC_offset[2] = 8;
Angel Pons88521882020-01-05 20:21:20 +0100319 ctrl->pi_coding_threshold = 10;
Angel Pons7c49cb82020-03-16 23:17:32 +0100320
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200321 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100322 ctrl->edge_offset[0] = 17; //XXX: guessed
323 ctrl->edge_offset[1] = 7;
324 ctrl->edge_offset[2] = 7;
325 ctrl->timC_offset[0] = 19; //XXX: guessed
326 ctrl->timC_offset[1] = 7;
327 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100328 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100329
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200330 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100331 ctrl->edge_offset[0] = 16;
332 ctrl->edge_offset[1] = 7;
333 ctrl->edge_offset[2] = 7;
334 ctrl->timC_offset[0] = 18;
335 ctrl->timC_offset[1] = 7;
336 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100337 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100338
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200339 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100340 ctrl->edge_offset[0] = 15; //XXX: guessed
341 ctrl->edge_offset[1] = 6;
342 ctrl->edge_offset[2] = 6;
343 ctrl->timC_offset[0] = 17; //XXX: guessed
344 ctrl->timC_offset[1] = 6;
345 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100346 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100347
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200348 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100349 ctrl->edge_offset[0] = 14;
350 ctrl->edge_offset[1] = 6;
351 ctrl->edge_offset[2] = 6;
352 ctrl->timC_offset[0] = 15;
353 ctrl->timC_offset[1] = 6;
354 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100355 ctrl->pi_coding_threshold = 15;
Angel Pons7c49cb82020-03-16 23:17:32 +0100356
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200357 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100358 ctrl->edge_offset[0] = 14; //XXX: guessed
359 ctrl->edge_offset[1] = 6;
360 ctrl->edge_offset[2] = 6;
361 ctrl->timC_offset[0] = 15; //XXX: guessed
362 ctrl->timC_offset[1] = 6;
363 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100364 ctrl->pi_coding_threshold = 12;
Angel Pons7c49cb82020-03-16 23:17:32 +0100365
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200366 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100367 ctrl->edge_offset[0] = 13;
368 ctrl->edge_offset[1] = 5;
369 ctrl->edge_offset[2] = 5;
370 ctrl->timC_offset[0] = 14;
371 ctrl->timC_offset[1] = 5;
372 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100373 ctrl->pi_coding_threshold = 15;
Angel Pons7c49cb82020-03-16 23:17:32 +0100374
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200375 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100376 ctrl->edge_offset[0] = 13; //XXX: guessed
377 ctrl->edge_offset[1] = 5;
378 ctrl->edge_offset[2] = 5;
379 ctrl->timC_offset[0] = 14; //XXX: guessed
380 ctrl->timC_offset[1] = 5;
381 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100382 ctrl->pi_coding_threshold = 16;
Angel Pons7c49cb82020-03-16 23:17:32 +0100383
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200384 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100385 ctrl->edge_offset[0] = 10;
386 ctrl->edge_offset[1] = 4;
387 ctrl->edge_offset[2] = 4;
388 ctrl->timC_offset[0] = 11;
389 ctrl->timC_offset[1] = 4;
390 ctrl->timC_offset[2] = 4;
Angel Pons88521882020-01-05 20:21:20 +0100391 ctrl->pi_coding_threshold = 16;
Angel Pons7c49cb82020-03-16 23:17:32 +0100392
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200393 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100394 ctrl->edge_offset[0] = 8;
395 ctrl->edge_offset[1] = 3;
396 ctrl->edge_offset[2] = 3;
397 ctrl->timC_offset[0] = 9;
398 ctrl->timC_offset[1] = 3;
399 ctrl->timC_offset[2] = 3;
Angel Pons88521882020-01-05 20:21:20 +0100400 ctrl->pi_coding_threshold = 17;
Angel Pons7c49cb82020-03-16 23:17:32 +0100401
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200402 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100403 ctrl->edge_offset[0] = 6;
404 ctrl->edge_offset[1] = 2;
405 ctrl->edge_offset[2] = 2;
406 ctrl->timC_offset[0] = 6;
407 ctrl->timC_offset[1] = 2;
408 ctrl->timC_offset[2] = 2;
Angel Pons88521882020-01-05 20:21:20 +0100409 ctrl->pi_coding_threshold = 17;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100410 }
411
412 /* Initial phase between CLK/CMD pins */
Angel Pons88521882020-01-05 20:21:20 +0100413 ctrl->pi_code_offset = (256000 / ctrl->tCK) / 66;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100414
415 /* DLL_CONFIG_MDLL_W_TIMER */
Angel Pons88521882020-01-05 20:21:20 +0100416 ctrl->mdll_wake_delay = (128000 / ctrl->tCK) + 3;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100417
Dan Elkoubydabebc32018-04-13 18:47:10 +0300418 if (ctrl->tCWL)
419 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
420 else
421 ctrl->CWL = get_CWL(ctrl->tCK);
Angel Pons7c49cb82020-03-16 23:17:32 +0100422
Patrick Rudolph305035c2016-11-11 18:38:50 +0100423 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
424
425 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100426 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100427 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
428
Angel Pons7c49cb82020-03-16 23:17:32 +0100429 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100430 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
431
432 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100433 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100434 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
435
436 /* Find tWR */
Angel Pons7c49cb82020-03-16 23:17:32 +0100437 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100438 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
439
440 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100441 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100442 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
443
444 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100445 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100446 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
447
448 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100449 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100450 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
451
452 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100453 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100454 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
455
456 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100457 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100458 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
459
Angel Pons7c49cb82020-03-16 23:17:32 +0100460 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
461 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100462 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
Angel Pons7c49cb82020-03-16 23:17:32 +0100463 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
464 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
465 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
466 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
467 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100468}
469
Angel Pons88521882020-01-05 20:21:20 +0100470static void dram_freq(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100471{
472 if (ctrl->tCK > TCK_400MHZ) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100473 printk(BIOS_ERR,
474 "DRAM frequency is under lowest supported frequency (400 MHz). "
475 "Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100476 ctrl->tCK = TCK_400MHZ;
477 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100478
Patrick Rudolph305035c2016-11-11 18:38:50 +0100479 while (1) {
480 u8 val2;
481 u32 reg1 = 0;
482
483 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200484 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100485
Angel Pons7c49cb82020-03-16 23:17:32 +0100486 /* Frequency multiplier */
487 const u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100488
Angel Pons7c49cb82020-03-16 23:17:32 +0100489 /*
490 * The PLL will never lock if the required frequency is already set.
491 * Exit early to prevent a system hang.
Patrick Rudolph305035c2016-11-11 18:38:50 +0100492 */
493 reg1 = MCHBAR32(MC_BIOS_DATA);
494 val2 = (u8) reg1;
495 if (val2)
496 return;
497
498 /* Step 2 - Select frequency in the MCU */
499 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100500 if (ctrl->base_freq == 100)
Angel Pons7c49cb82020-03-16 23:17:32 +0100501 reg1 |= 0x100; /* Enable 100Mhz REF clock */
502
503 reg1 |= 0x80000000; /* set running bit */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100504 MCHBAR32(MC_BIOS_REQ) = reg1;
Angel Pons7c49cb82020-03-16 23:17:32 +0100505 int i = 0;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100506 printk(BIOS_DEBUG, "PLL busy... ");
507 while (reg1 & 0x80000000) {
508 udelay(10);
509 i++;
510 reg1 = MCHBAR32(MC_BIOS_REQ);
511 }
512 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
513
514 /* Step 3 - Verify lock frequency */
515 reg1 = MCHBAR32(MC_BIOS_DATA);
516 val2 = (u8) reg1;
517 if (val2 >= FRQ) {
518 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
519 (1000 << 8) / ctrl->tCK);
520 return;
521 }
522 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
523 ctrl->tCK++;
524 }
525}
526
Angel Pons88521882020-01-05 20:21:20 +0100527static void dram_ioregs(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100528{
Angel Pons7c49cb82020-03-16 23:17:32 +0100529 u32 reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100530
531 int channel;
532
Angel Pons7c49cb82020-03-16 23:17:32 +0100533 /* IO clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100534 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100535 MCHBAR32(GDCRCLKRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100536 }
537
Angel Pons7c49cb82020-03-16 23:17:32 +0100538 /* IO command */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100539 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100540 MCHBAR32(GDCRCTLRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100541 }
542
Angel Pons7c49cb82020-03-16 23:17:32 +0100543 /* IO control */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100544 FOR_ALL_POPULATED_CHANNELS {
545 program_timings(ctrl, channel);
546 }
547
Angel Pons7c49cb82020-03-16 23:17:32 +0100548 /* Perform RCOMP */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100549 printram("RCOMP...");
Angel Pons7c49cb82020-03-16 23:17:32 +0100550 while (!(MCHBAR32(RCOMP_TIMER) & (1 << 16)))
551 ;
552
Patrick Rudolph305035c2016-11-11 18:38:50 +0100553 printram("done\n");
554
Angel Pons7c49cb82020-03-16 23:17:32 +0100555 /* Set COMP2 */
556 MCHBAR32(CRCOMPOFST2) = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100557 printram("COMP2 done\n");
558
Angel Pons7c49cb82020-03-16 23:17:32 +0100559 /* Set COMP1 */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100560 FOR_ALL_POPULATED_CHANNELS {
Angel Pons7c49cb82020-03-16 23:17:32 +0100561 reg = MCHBAR32(CRCOMPOFST1_ch(channel));
562 reg = (reg & ~0x00000e00) | (1 << 9); /* ODT */
563 reg = (reg & ~0x00e00000) | (1 << 21); /* clk drive up */
564 reg = (reg & ~0x38000000) | (1 << 27); /* ctl drive up */
Angel Pons88521882020-01-05 20:21:20 +0100565 MCHBAR32(CRCOMPOFST1_ch(channel)) = reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100566 }
567 printram("COMP1 done\n");
568
569 printram("FORCE RCOMP and wait 20us...");
Angel Pons7c49cb82020-03-16 23:17:32 +0100570 MCHBAR32(M_COMP) |= (1 << 8);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100571 udelay(20);
572 printram("done\n");
573}
574
Angel Pons7c49cb82020-03-16 23:17:32 +0100575int try_init_dram_ddr3_ivb(ramctr_timing *ctrl, int fast_boot, int s3_resume, int me_uma_size)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100576{
577 int err;
578
Angel Pons7c49cb82020-03-16 23:17:32 +0100579 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n", fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100580
581 if (!fast_boot) {
582 /* Find fastest common supported parameters */
583 dram_find_common_params(ctrl);
584
585 dram_dimm_mapping(ctrl);
586 }
587
Angel Pons7c49cb82020-03-16 23:17:32 +0100588 /* Set MC frequency */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100589 dram_freq(ctrl);
590
591 if (!fast_boot) {
592 /* Calculate timings */
593 dram_timing(ctrl);
594 }
595
596 /* Set version register */
Angel Pons7c49cb82020-03-16 23:17:32 +0100597 MCHBAR32(MRC_REVISION) = 0xc04eb002;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100598
599 /* Enable crossover */
600 dram_xover(ctrl);
601
602 /* Set timing and refresh registers */
603 dram_timing_regs(ctrl);
604
605 /* Power mode preset */
Angel Pons88521882020-01-05 20:21:20 +0100606 MCHBAR32(PM_THML_STAT) = 0x5500;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100607
Angel Pons88521882020-01-05 20:21:20 +0100608 /* Set scheduler chicken bits */
609 MCHBAR32(SCHED_CBIT) = 0x10100005;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100610
Angel Pons7c49cb82020-03-16 23:17:32 +0100611 /* Set up watermarks and starvation counter */
612 set_wmm_behavior();
Patrick Rudolph305035c2016-11-11 18:38:50 +0100613
614 /* Clear IO reset bit */
Angel Pons7c49cb82020-03-16 23:17:32 +0100615 MCHBAR32(MC_INIT_STATE_G) &= ~(1 << 5);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100616
617 /* Set MAD-DIMM registers */
618 dram_dimm_set_mapping(ctrl);
619 printk(BIOS_DEBUG, "Done dimm mapping\n");
620
621 /* Zone config */
622 dram_zones(ctrl, 1);
623
624 /* Set memory map */
625 dram_memorymap(ctrl, me_uma_size);
626 printk(BIOS_DEBUG, "Done memory map\n");
627
628 /* Set IO registers */
629 dram_ioregs(ctrl);
630 printk(BIOS_DEBUG, "Done io registers\n");
631
632 udelay(1);
633
634 if (fast_boot) {
635 restore_timings(ctrl);
636 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100637 /* Do JEDEC DDR3 reset sequence */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100638 dram_jedecreset(ctrl);
639 printk(BIOS_DEBUG, "Done jedec reset\n");
640
641 /* MRS commands */
642 dram_mrscommands(ctrl);
643 printk(BIOS_DEBUG, "Done MRS commands\n");
644
645 /* Prepare for memory training */
646 prepare_training(ctrl);
647
648 err = read_training(ctrl);
649 if (err)
650 return err;
651
652 err = write_training(ctrl);
653 if (err)
654 return err;
655
656 printram("CP5a\n");
657
658 err = discover_edges(ctrl);
659 if (err)
660 return err;
661
662 printram("CP5b\n");
663
664 err = command_training(ctrl);
665 if (err)
666 return err;
667
668 printram("CP5c\n");
669
670 err = discover_edges_write(ctrl);
671 if (err)
672 return err;
673
674 err = discover_timC_write(ctrl);
675 if (err)
676 return err;
677
678 normalize_training(ctrl);
679 }
680
Angel Pons7c49cb82020-03-16 23:17:32 +0100681 set_read_write_timings(ctrl);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100682
683 write_controller_mr(ctrl);
684
685 if (!s3_resume) {
686 err = channel_test(ctrl);
687 if (err)
688 return err;
689 }
690
691 return 0;
692}