blob: 3dcdaba4f92761f4e4e1982caf5098274c5d5bef [file] [log] [blame]
Angel Pons6e5aabd2020-03-23 23:44:42 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Patrick Rudolph305035c2016-11-11 18:38:50 +01003
4#include <console/console.h>
5#include <console/usb.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +01006#include <delay.h>
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +01007#include <device/pci_ops.h>
Patrick Rudolph305035c2016-11-11 18:38:50 +01008#include "raminit_native.h"
9#include "raminit_common.h"
10
Angel Pons7c49cb82020-03-16 23:17:32 +010011/* Frequency multiplier */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010012static u32 get_FRQ(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010013{
Angel Pons7c49cb82020-03-16 23:17:32 +010014 const u32 FRQ = 256000 / (tCK * base_freq);
Patrick Rudolph77eaba32016-11-11 18:55:54 +010015
16 if (base_freq == 100) {
17 if (FRQ > 12)
18 return 12;
19 if (FRQ < 7)
20 return 7;
21 } else {
22 if (FRQ > 10)
23 return 10;
24 if (FRQ < 3)
25 return 3;
26 }
27
Patrick Rudolph305035c2016-11-11 18:38:50 +010028 return FRQ;
29}
30
Angel Pons7c49cb82020-03-16 23:17:32 +010031/* Get REFI based on MC frequency, tREFI = 7.8usec */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010032static u32 get_REFI(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010033{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010034 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010035 static const u32 frq_xs_map[] = {
36 /* FRQ: 7, 8, 9, 10, 11, 12, */
37 5460, 6240, 7020, 7800, 8580, 9360,
38 };
39 return frq_xs_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010040
Angel Pons7c49cb82020-03-16 23:17:32 +010041 } else {
42 static const u32 frq_refi_map[] = {
43 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
44 3120, 4160, 5200, 6240, 7280, 8320, 9360, 10400,
45 };
46 return frq_refi_map[get_FRQ(tCK, 133) - 3];
47 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010048}
49
Angel Pons7c49cb82020-03-16 23:17:32 +010050/* Get XSOffset based on MC frequency, tXS-Offset: tXS = tRFC + 10ns */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010051static u8 get_XSOffset(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010052{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010053 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010054 static const u8 frq_xs_map[] = {
55 /* FRQ: 7, 8, 9, 10, 11, 12, */
56 7, 8, 9, 10, 11, 12,
57 };
58 return frq_xs_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010059
Angel Pons7c49cb82020-03-16 23:17:32 +010060 } else {
61 static const u8 frq_xs_map[] = {
62 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
63 4, 6, 7, 8, 10, 11, 12, 14,
64 };
65 return frq_xs_map[get_FRQ(tCK, 133) - 3];
66 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010067}
68
Angel Pons7c49cb82020-03-16 23:17:32 +010069/* Get MOD based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010070static u8 get_MOD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010071{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010072 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010073 static const u8 frq_mod_map[] = {
74 /* FRQ: 7, 8, 9, 10, 11, 12, */
75 12, 12, 14, 15, 17, 18,
76 };
77 return frq_mod_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010078
Patrick Rudolph77eaba32016-11-11 18:55:54 +010079 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +010080 static const u8 frq_mod_map[] = {
81 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
82 12, 12, 12, 12, 15, 16, 18, 20,
83 };
84 return frq_mod_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010085 }
Patrick Rudolph305035c2016-11-11 18:38:50 +010086}
87
Angel Pons7c49cb82020-03-16 23:17:32 +010088/* Get Write Leveling Output delay based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +010089static u8 get_WLO(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +010090{
Patrick Rudolph77eaba32016-11-11 18:55:54 +010091 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +010092 static const u8 frq_wlo_map[] = {
93 /* FRQ: 7, 8, 9, 10, 11, 12, */
94 6, 6, 7, 8, 9, 9,
95 };
96 return frq_wlo_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +010097
Patrick Rudolph77eaba32016-11-11 18:55:54 +010098 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +010099 static const u8 frq_wlo_map[] = {
100 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
101 4, 5, 6, 6, 8, 8, 9, 10,
102 };
103 return frq_wlo_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100104 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100105}
106
Angel Pons7c49cb82020-03-16 23:17:32 +0100107/* Get CKE based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100108static u8 get_CKE(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100109{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100110 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100111 static const u8 frq_cke_map[] = {
112 /* FRQ: 7, 8, 9, 10, 11, 12, */
113 4, 4, 5, 5, 6, 6,
114 };
115 return frq_cke_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100116
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100117 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100118 static const u8 frq_cke_map[] = {
119 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
120 3, 3, 4, 4, 5, 6, 6, 7,
121 };
122 return frq_cke_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100123 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100124}
125
Angel Pons7c49cb82020-03-16 23:17:32 +0100126/* Get XPDLL based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100127static u8 get_XPDLL(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100128{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100129 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100130 static const u8 frq_xpdll_map[] = {
131 /* FRQ: 7, 8, 9, 10, 11, 12, */
132 17, 20, 22, 24, 27, 32,
133 };
134 return frq_xpdll_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100135
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100136 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100137 static const u8 frq_xpdll_map[] = {
138 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
139 10, 13, 16, 20, 23, 26, 29, 32,
140 };
141 return frq_xpdll_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100142 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100143}
144
Angel Pons7c49cb82020-03-16 23:17:32 +0100145/* Get XP based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100146static u8 get_XP(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100147{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100148 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100149 static const u8 frq_xp_map[] = {
150 /* FRQ: 7, 8, 9, 10, 11, 12, */
151 5, 5, 6, 6, 7, 8,
152 };
153 return frq_xp_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100154 } else {
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100155
Angel Pons7c49cb82020-03-16 23:17:32 +0100156 static const u8 frq_xp_map[] = {
157 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
158 3, 4, 4, 5, 6, 7, 8, 8
159 };
160 return frq_xp_map[get_FRQ(tCK, 133) - 3];
161 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100162}
163
Angel Pons7c49cb82020-03-16 23:17:32 +0100164/* Get AONPD based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100165static u8 get_AONPD(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100166{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100167 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100168 static const u8 frq_aonpd_map[] = {
169 /* FRQ: 7, 8, 9, 10, 11, 12, */
170 6, 8, 8, 9, 10, 11,
171 };
172 return frq_aonpd_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100173
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100174 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100175 static const u8 frq_aonpd_map[] = {
176 /* FRQ: 3, 4, 5, 6, 7, 8, 9, 10, */
177 4, 5, 6, 8, 8, 10, 11, 12,
178 };
179 return frq_aonpd_map[get_FRQ(tCK, 133) - 3];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100180 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100181}
182
Angel Pons7c49cb82020-03-16 23:17:32 +0100183/* Get COMP2 based on MC frequency */
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100184static u32 get_COMP2(u32 tCK, u8 base_freq)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100185{
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100186 if (base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100187 static const u32 frq_comp2_map[] = {
188 // FRQ: 7, 8, 9, 10, 11, 12,
189 0x0CA8C264, 0x0C6671E4, 0x0C6671E4, 0x0C446964, 0x0C235924, 0x0C235924,
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100190 };
Angel Pons7c49cb82020-03-16 23:17:32 +0100191 return frq_comp2_map[get_FRQ(tCK, 100) - 7];
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100192
Angel Pons7c49cb82020-03-16 23:17:32 +0100193 } else {
194 static const u32 frq_comp2_map[] = {
195 /* FRQ: 3, 4, 5, 6, */
196 0x0D6FF5E4, 0x0CEBDB64, 0x0CA8C264, 0x0C6671E4,
197
198 /* FRQ: 7, 8, 9, 10, */
199 0x0C446964, 0x0C235924, 0x0C235924, 0x0C235924,
200 };
201 return frq_comp2_map[get_FRQ(tCK, 133) - 3];
202 }
Patrick Rudolph305035c2016-11-11 18:38:50 +0100203}
204
Angel Pons7c49cb82020-03-16 23:17:32 +0100205static void ivb_normalize_tclk(ramctr_timing *ctrl, bool ref_100mhz_support)
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200206{
207 if (ctrl->tCK <= TCK_1200MHZ) {
208 ctrl->tCK = TCK_1200MHZ;
209 ctrl->base_freq = 100;
210 } else if (ctrl->tCK <= TCK_1100MHZ) {
211 ctrl->tCK = TCK_1100MHZ;
212 ctrl->base_freq = 100;
213 } else if (ctrl->tCK <= TCK_1066MHZ) {
214 ctrl->tCK = TCK_1066MHZ;
215 ctrl->base_freq = 133;
216 } else if (ctrl->tCK <= TCK_1000MHZ) {
217 ctrl->tCK = TCK_1000MHZ;
218 ctrl->base_freq = 100;
219 } else if (ctrl->tCK <= TCK_933MHZ) {
220 ctrl->tCK = TCK_933MHZ;
221 ctrl->base_freq = 133;
222 } else if (ctrl->tCK <= TCK_900MHZ) {
223 ctrl->tCK = TCK_900MHZ;
224 ctrl->base_freq = 100;
225 } else if (ctrl->tCK <= TCK_800MHZ) {
226 ctrl->tCK = TCK_800MHZ;
227 ctrl->base_freq = 133;
228 } else if (ctrl->tCK <= TCK_700MHZ) {
229 ctrl->tCK = TCK_700MHZ;
230 ctrl->base_freq = 100;
231 } else if (ctrl->tCK <= TCK_666MHZ) {
232 ctrl->tCK = TCK_666MHZ;
233 ctrl->base_freq = 133;
234 } else if (ctrl->tCK <= TCK_533MHZ) {
235 ctrl->tCK = TCK_533MHZ;
236 ctrl->base_freq = 133;
237 } else if (ctrl->tCK <= TCK_400MHZ) {
238 ctrl->tCK = TCK_400MHZ;
239 ctrl->base_freq = 133;
240 } else {
241 ctrl->tCK = 0;
242 return;
243 }
244
245 if (!ref_100mhz_support && ctrl->base_freq == 100) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100246 /* Skip unsupported frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200247 ctrl->tCK++;
248 ivb_normalize_tclk(ctrl, ref_100mhz_support);
249 }
250}
251
252static void find_cas_tck(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100253{
254 u8 val;
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200255 u32 reg32;
256 u8 ref_100mhz_support;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100257
Angel Pons7c49cb82020-03-16 23:17:32 +0100258 /* 100 MHz reference clock supported */
259 reg32 = pci_read_config32(HOST_BRIDGE, CAPID0_B);
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200260 ref_100mhz_support = !!((reg32 >> 21) & 0x7);
Angel Pons7c49cb82020-03-16 23:17:32 +0100261 printk(BIOS_DEBUG, "100MHz reference clock support: %s\n", ref_100mhz_support ? "yes"
262 : "no");
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200263
264 /* Find CAS latency */
265 while (1) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100266 /*
267 * Normalising tCK before computing clock could potentially
268 * result in a lower selected CAS, which is desired.
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200269 */
270 ivb_normalize_tclk(ctrl, ref_100mhz_support);
271 if (!(ctrl->tCK))
272 die("Couldn't find compatible clock / CAS settings\n");
Angel Pons7c49cb82020-03-16 23:17:32 +0100273
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200274 val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK);
275 printk(BIOS_DEBUG, "Trying CAS %u, tCK %u.\n", val, ctrl->tCK);
276 for (; val <= MAX_CAS; val++)
277 if ((ctrl->cas_supported >> (val - MIN_CAS)) & 1)
278 break;
Angel Pons7c49cb82020-03-16 23:17:32 +0100279
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200280 if (val == (MAX_CAS + 1)) {
281 ctrl->tCK++;
282 continue;
283 } else {
284 printk(BIOS_DEBUG, "Found compatible clock, CAS pair.\n");
285 break;
286 }
287 }
288
Angel Pons7c49cb82020-03-16 23:17:32 +0100289 printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", NS2MHZ_DIV256 / ctrl->tCK);
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200290 printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val);
291 ctrl->CAS = val;
292}
293
294
295static void dram_timing(ramctr_timing *ctrl)
296{
Angel Pons7c49cb82020-03-16 23:17:32 +0100297 /*
298 * On Ivy Bridge, the maximum supported DDR3 frequency is 1400MHz (DDR3 2800).
299 * Cap it at 1200MHz (DDR3 2400), and align it to the closest JEDEC standard frequency.
300 */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200301 if (ctrl->tCK == TCK_1200MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100302 ctrl->edge_offset[0] = 18; //XXX: guessed
303 ctrl->edge_offset[1] = 8;
304 ctrl->edge_offset[2] = 8;
305 ctrl->timC_offset[0] = 20; //XXX: guessed
306 ctrl->timC_offset[1] = 8;
307 ctrl->timC_offset[2] = 8;
Angel Pons88521882020-01-05 20:21:20 +0100308 ctrl->pi_coding_threshold = 10;
Angel Pons7c49cb82020-03-16 23:17:32 +0100309
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200310 } else if (ctrl->tCK == TCK_1100MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100311 ctrl->edge_offset[0] = 17; //XXX: guessed
312 ctrl->edge_offset[1] = 7;
313 ctrl->edge_offset[2] = 7;
314 ctrl->timC_offset[0] = 19; //XXX: guessed
315 ctrl->timC_offset[1] = 7;
316 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100317 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100318
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200319 } else if (ctrl->tCK == TCK_1066MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100320 ctrl->edge_offset[0] = 16;
321 ctrl->edge_offset[1] = 7;
322 ctrl->edge_offset[2] = 7;
323 ctrl->timC_offset[0] = 18;
324 ctrl->timC_offset[1] = 7;
325 ctrl->timC_offset[2] = 7;
Angel Pons88521882020-01-05 20:21:20 +0100326 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100327
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200328 } else if (ctrl->tCK == TCK_1000MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100329 ctrl->edge_offset[0] = 15; //XXX: guessed
330 ctrl->edge_offset[1] = 6;
331 ctrl->edge_offset[2] = 6;
332 ctrl->timC_offset[0] = 17; //XXX: guessed
333 ctrl->timC_offset[1] = 6;
334 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100335 ctrl->pi_coding_threshold = 13;
Angel Pons7c49cb82020-03-16 23:17:32 +0100336
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200337 } else if (ctrl->tCK == TCK_933MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100338 ctrl->edge_offset[0] = 14;
339 ctrl->edge_offset[1] = 6;
340 ctrl->edge_offset[2] = 6;
341 ctrl->timC_offset[0] = 15;
342 ctrl->timC_offset[1] = 6;
343 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100344 ctrl->pi_coding_threshold = 15;
Angel Pons7c49cb82020-03-16 23:17:32 +0100345
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200346 } else if (ctrl->tCK == TCK_900MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100347 ctrl->edge_offset[0] = 14; //XXX: guessed
348 ctrl->edge_offset[1] = 6;
349 ctrl->edge_offset[2] = 6;
350 ctrl->timC_offset[0] = 15; //XXX: guessed
351 ctrl->timC_offset[1] = 6;
352 ctrl->timC_offset[2] = 6;
Angel Pons88521882020-01-05 20:21:20 +0100353 ctrl->pi_coding_threshold = 12;
Angel Pons7c49cb82020-03-16 23:17:32 +0100354
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200355 } else if (ctrl->tCK == TCK_800MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100356 ctrl->edge_offset[0] = 13;
357 ctrl->edge_offset[1] = 5;
358 ctrl->edge_offset[2] = 5;
359 ctrl->timC_offset[0] = 14;
360 ctrl->timC_offset[1] = 5;
361 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100362 ctrl->pi_coding_threshold = 15;
Angel Pons7c49cb82020-03-16 23:17:32 +0100363
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200364 } else if (ctrl->tCK == TCK_700MHZ) {
Patrick Rudolphcb7d6a12016-11-25 15:40:49 +0100365 ctrl->edge_offset[0] = 13; //XXX: guessed
366 ctrl->edge_offset[1] = 5;
367 ctrl->edge_offset[2] = 5;
368 ctrl->timC_offset[0] = 14; //XXX: guessed
369 ctrl->timC_offset[1] = 5;
370 ctrl->timC_offset[2] = 5;
Angel Pons88521882020-01-05 20:21:20 +0100371 ctrl->pi_coding_threshold = 16;
Angel Pons7c49cb82020-03-16 23:17:32 +0100372
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200373 } else if (ctrl->tCK == TCK_666MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100374 ctrl->edge_offset[0] = 10;
375 ctrl->edge_offset[1] = 4;
376 ctrl->edge_offset[2] = 4;
377 ctrl->timC_offset[0] = 11;
378 ctrl->timC_offset[1] = 4;
379 ctrl->timC_offset[2] = 4;
Angel Pons88521882020-01-05 20:21:20 +0100380 ctrl->pi_coding_threshold = 16;
Angel Pons7c49cb82020-03-16 23:17:32 +0100381
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200382 } else if (ctrl->tCK == TCK_533MHZ) {
Patrick Rudolph305035c2016-11-11 18:38:50 +0100383 ctrl->edge_offset[0] = 8;
384 ctrl->edge_offset[1] = 3;
385 ctrl->edge_offset[2] = 3;
386 ctrl->timC_offset[0] = 9;
387 ctrl->timC_offset[1] = 3;
388 ctrl->timC_offset[2] = 3;
Angel Pons88521882020-01-05 20:21:20 +0100389 ctrl->pi_coding_threshold = 17;
Angel Pons7c49cb82020-03-16 23:17:32 +0100390
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200391 } else { /* TCK_400MHZ */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100392 ctrl->edge_offset[0] = 6;
393 ctrl->edge_offset[1] = 2;
394 ctrl->edge_offset[2] = 2;
395 ctrl->timC_offset[0] = 6;
396 ctrl->timC_offset[1] = 2;
397 ctrl->timC_offset[2] = 2;
Angel Pons88521882020-01-05 20:21:20 +0100398 ctrl->pi_coding_threshold = 17;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100399 }
400
401 /* Initial phase between CLK/CMD pins */
Angel Pons88521882020-01-05 20:21:20 +0100402 ctrl->pi_code_offset = (256000 / ctrl->tCK) / 66;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100403
404 /* DLL_CONFIG_MDLL_W_TIMER */
Angel Pons88521882020-01-05 20:21:20 +0100405 ctrl->mdll_wake_delay = (128000 / ctrl->tCK) + 3;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100406
Dan Elkoubydabebc32018-04-13 18:47:10 +0300407 if (ctrl->tCWL)
408 ctrl->CWL = DIV_ROUND_UP(ctrl->tCWL, ctrl->tCK);
409 else
410 ctrl->CWL = get_CWL(ctrl->tCK);
Angel Pons7c49cb82020-03-16 23:17:32 +0100411
Patrick Rudolph305035c2016-11-11 18:38:50 +0100412 printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL);
413
414 /* Find tRCD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100415 ctrl->tRCD = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100416 printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD);
417
Angel Pons7c49cb82020-03-16 23:17:32 +0100418 ctrl->tRP = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100419 printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP);
420
421 /* Find tRAS */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100422 ctrl->tRAS = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100423 printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS);
424
425 /* Find tWR */
Angel Pons7c49cb82020-03-16 23:17:32 +0100426 ctrl->tWR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100427 printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR);
428
429 /* Find tFAW */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100430 ctrl->tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100431 printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW);
432
433 /* Find tRRD */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100434 ctrl->tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100435 printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD);
436
437 /* Find tRTP */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100438 ctrl->tRTP = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100439 printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP);
440
441 /* Find tWTR */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100442 ctrl->tWTR = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100443 printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR);
444
445 /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */
Arthur Heymans50db9c92017-03-23 18:53:38 +0100446 ctrl->tRFC = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100447 printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC);
448
Angel Pons7c49cb82020-03-16 23:17:32 +0100449 ctrl->tREFI = get_REFI(ctrl->tCK, ctrl->base_freq);
450 ctrl->tMOD = get_MOD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100451 ctrl->tXSOffset = get_XSOffset(ctrl->tCK, ctrl->base_freq);
Angel Pons7c49cb82020-03-16 23:17:32 +0100452 ctrl->tWLO = get_WLO(ctrl->tCK, ctrl->base_freq);
453 ctrl->tCKE = get_CKE(ctrl->tCK, ctrl->base_freq);
454 ctrl->tXPDLL = get_XPDLL(ctrl->tCK, ctrl->base_freq);
455 ctrl->tXP = get_XP(ctrl->tCK, ctrl->base_freq);
456 ctrl->tAONPD = get_AONPD(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100457}
458
Angel Pons88521882020-01-05 20:21:20 +0100459static void dram_freq(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100460{
461 if (ctrl->tCK > TCK_400MHZ) {
Angel Pons7c49cb82020-03-16 23:17:32 +0100462 printk(BIOS_ERR,
463 "DRAM frequency is under lowest supported frequency (400 MHz). "
464 "Increasing to 400 MHz as last resort");
Patrick Rudolph305035c2016-11-11 18:38:50 +0100465 ctrl->tCK = TCK_400MHZ;
466 }
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100467
Patrick Rudolph305035c2016-11-11 18:38:50 +0100468 while (1) {
469 u8 val2;
470 u32 reg1 = 0;
471
472 /* Step 1 - Set target PCU frequency */
Arthur Heymans9ed74b52017-05-16 19:56:49 +0200473 find_cas_tck(ctrl);
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100474
Angel Pons7c49cb82020-03-16 23:17:32 +0100475 /* Frequency multiplier */
476 const u32 FRQ = get_FRQ(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100477
Angel Pons7c49cb82020-03-16 23:17:32 +0100478 /*
479 * The PLL will never lock if the required frequency is already set.
480 * Exit early to prevent a system hang.
Patrick Rudolph305035c2016-11-11 18:38:50 +0100481 */
482 reg1 = MCHBAR32(MC_BIOS_DATA);
483 val2 = (u8) reg1;
484 if (val2)
485 return;
486
487 /* Step 2 - Select frequency in the MCU */
488 reg1 = FRQ;
Patrick Rudolphcab4d3d2016-11-24 19:40:23 +0100489 if (ctrl->base_freq == 100)
Angel Pons7c49cb82020-03-16 23:17:32 +0100490 reg1 |= 0x100; /* Enable 100Mhz REF clock */
491
492 reg1 |= 0x80000000; /* set running bit */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100493 MCHBAR32(MC_BIOS_REQ) = reg1;
Angel Pons7c49cb82020-03-16 23:17:32 +0100494 int i = 0;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100495 printk(BIOS_DEBUG, "PLL busy... ");
496 while (reg1 & 0x80000000) {
497 udelay(10);
498 i++;
499 reg1 = MCHBAR32(MC_BIOS_REQ);
500 }
501 printk(BIOS_DEBUG, "done in %d us\n", i * 10);
502
503 /* Step 3 - Verify lock frequency */
504 reg1 = MCHBAR32(MC_BIOS_DATA);
505 val2 = (u8) reg1;
506 if (val2 >= FRQ) {
507 printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n",
508 (1000 << 8) / ctrl->tCK);
509 return;
510 }
511 printk(BIOS_DEBUG, "PLL didn't lock. Retrying at lower frequency\n");
512 ctrl->tCK++;
513 }
514}
515
Angel Pons88521882020-01-05 20:21:20 +0100516static void dram_ioregs(ramctr_timing *ctrl)
Patrick Rudolph305035c2016-11-11 18:38:50 +0100517{
Angel Pons7c49cb82020-03-16 23:17:32 +0100518 u32 reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100519
520 int channel;
521
Angel Pons7c49cb82020-03-16 23:17:32 +0100522 /* IO clock */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100523 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100524 MCHBAR32(GDCRCLKRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100525 }
526
Angel Pons7c49cb82020-03-16 23:17:32 +0100527 /* IO command */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100528 FOR_ALL_CHANNELS {
Angel Pons88521882020-01-05 20:21:20 +0100529 MCHBAR32(GDCRCTLRANKSUSED_ch(channel)) = ctrl->rankmap[channel];
Patrick Rudolph305035c2016-11-11 18:38:50 +0100530 }
531
Angel Pons7c49cb82020-03-16 23:17:32 +0100532 /* IO control */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100533 FOR_ALL_POPULATED_CHANNELS {
534 program_timings(ctrl, channel);
535 }
536
Angel Pons7c49cb82020-03-16 23:17:32 +0100537 /* Perform RCOMP */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100538 printram("RCOMP...");
Angel Pons7c49cb82020-03-16 23:17:32 +0100539 while (!(MCHBAR32(RCOMP_TIMER) & (1 << 16)))
540 ;
541
Patrick Rudolph305035c2016-11-11 18:38:50 +0100542 printram("done\n");
543
Angel Pons7c49cb82020-03-16 23:17:32 +0100544 /* Set COMP2 */
545 MCHBAR32(CRCOMPOFST2) = get_COMP2(ctrl->tCK, ctrl->base_freq);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100546 printram("COMP2 done\n");
547
Angel Pons7c49cb82020-03-16 23:17:32 +0100548 /* Set COMP1 */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100549 FOR_ALL_POPULATED_CHANNELS {
Angel Pons7c49cb82020-03-16 23:17:32 +0100550 reg = MCHBAR32(CRCOMPOFST1_ch(channel));
551 reg = (reg & ~0x00000e00) | (1 << 9); /* ODT */
552 reg = (reg & ~0x00e00000) | (1 << 21); /* clk drive up */
553 reg = (reg & ~0x38000000) | (1 << 27); /* ctl drive up */
Angel Pons88521882020-01-05 20:21:20 +0100554 MCHBAR32(CRCOMPOFST1_ch(channel)) = reg;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100555 }
556 printram("COMP1 done\n");
557
558 printram("FORCE RCOMP and wait 20us...");
Angel Pons7c49cb82020-03-16 23:17:32 +0100559 MCHBAR32(M_COMP) |= (1 << 8);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100560 udelay(20);
561 printram("done\n");
562}
563
Angel Pons7c49cb82020-03-16 23:17:32 +0100564int 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 +0100565{
566 int err;
567
Angel Pons7c49cb82020-03-16 23:17:32 +0100568 printk(BIOS_DEBUG, "Starting Ivybridge RAM training (%d).\n", fast_boot);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100569
570 if (!fast_boot) {
571 /* Find fastest common supported parameters */
572 dram_find_common_params(ctrl);
573
574 dram_dimm_mapping(ctrl);
575 }
576
Angel Pons7c49cb82020-03-16 23:17:32 +0100577 /* Set MC frequency */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100578 dram_freq(ctrl);
579
580 if (!fast_boot) {
581 /* Calculate timings */
582 dram_timing(ctrl);
583 }
584
585 /* Set version register */
Angel Pons7c49cb82020-03-16 23:17:32 +0100586 MCHBAR32(MRC_REVISION) = 0xc04eb002;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100587
588 /* Enable crossover */
589 dram_xover(ctrl);
590
591 /* Set timing and refresh registers */
592 dram_timing_regs(ctrl);
593
594 /* Power mode preset */
Angel Pons88521882020-01-05 20:21:20 +0100595 MCHBAR32(PM_THML_STAT) = 0x5500;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100596
Angel Pons88521882020-01-05 20:21:20 +0100597 /* Set scheduler chicken bits */
598 MCHBAR32(SCHED_CBIT) = 0x10100005;
Patrick Rudolph305035c2016-11-11 18:38:50 +0100599
Angel Pons7c49cb82020-03-16 23:17:32 +0100600 /* Set up watermarks and starvation counter */
Angel Pons89ae6b82020-03-21 13:23:32 +0100601 set_wmm_behavior(ctrl->cpu);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100602
603 /* Clear IO reset bit */
Angel Pons7c49cb82020-03-16 23:17:32 +0100604 MCHBAR32(MC_INIT_STATE_G) &= ~(1 << 5);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100605
606 /* Set MAD-DIMM registers */
607 dram_dimm_set_mapping(ctrl);
608 printk(BIOS_DEBUG, "Done dimm mapping\n");
609
610 /* Zone config */
611 dram_zones(ctrl, 1);
612
613 /* Set memory map */
614 dram_memorymap(ctrl, me_uma_size);
615 printk(BIOS_DEBUG, "Done memory map\n");
616
617 /* Set IO registers */
618 dram_ioregs(ctrl);
619 printk(BIOS_DEBUG, "Done io registers\n");
620
621 udelay(1);
622
623 if (fast_boot) {
624 restore_timings(ctrl);
625 } else {
Angel Pons7c49cb82020-03-16 23:17:32 +0100626 /* Do JEDEC DDR3 reset sequence */
Patrick Rudolph305035c2016-11-11 18:38:50 +0100627 dram_jedecreset(ctrl);
628 printk(BIOS_DEBUG, "Done jedec reset\n");
629
630 /* MRS commands */
631 dram_mrscommands(ctrl);
632 printk(BIOS_DEBUG, "Done MRS commands\n");
633
634 /* Prepare for memory training */
635 prepare_training(ctrl);
636
637 err = read_training(ctrl);
638 if (err)
639 return err;
640
641 err = write_training(ctrl);
642 if (err)
643 return err;
644
645 printram("CP5a\n");
646
647 err = discover_edges(ctrl);
648 if (err)
649 return err;
650
651 printram("CP5b\n");
652
653 err = command_training(ctrl);
654 if (err)
655 return err;
656
657 printram("CP5c\n");
658
659 err = discover_edges_write(ctrl);
660 if (err)
661 return err;
662
663 err = discover_timC_write(ctrl);
664 if (err)
665 return err;
666
667 normalize_training(ctrl);
668 }
669
Angel Pons7c49cb82020-03-16 23:17:32 +0100670 set_read_write_timings(ctrl);
Patrick Rudolph305035c2016-11-11 18:38:50 +0100671
672 write_controller_mr(ctrl);
673
674 if (!s3_resume) {
675 err = channel_test(ctrl);
676 if (err)
677 return err;
678 }
679
680 return 0;
681}