blob: afdd9084c41df6677b7a7cd86323c76bbe83c0c7 [file] [log] [blame]
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +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>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010019#include <string.h>
Subrata Banik53b08c32018-12-10 14:11:35 +053020#include <arch/cpu.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010021#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010023#include <northbridge/intel/sandybridge/chip.h>
24#include <device/pci_def.h>
25#include <delay.h>
26#include <arch/cpu.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010027#include "raminit_native.h"
28#include "raminit_common.h"
29#include "sandybridge.h"
30
31/* FIXME: no ECC support. */
32/* FIXME: no support for 3-channel chipsets. */
33
34/*
35 * Register description:
36 * Intel provides a command queue of depth four.
37 * Every command is configured by using multiple registers.
38 * On executing the command queue you have to provide the depth used.
39 *
40 * Known registers:
41 * Channel X = [0, 1]
42 * Command queue index Y = [0, 1, 2, 3]
43 *
44 * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register
45 * Controls the DRAM command signals
46 * Bit 0: !RAS
47 * Bit 1: !CAS
48 * Bit 2: !WE
49 *
50 * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register
51 * Controls the address, bank address and slotrank signals
52 * Bit 0-15 : Address
53 * Bit 20-22: Bank Address
54 * Bit 24-25: slotrank
55 *
56 * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register
57 * Controls the idle time after issuing this DRAM command
58 * Bit 16-32: number of clock-cylces to idle
59 *
60 * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue
61 * Starts to execute all queued commands
62 * Bit 0 : start DRAM command execution
Felix Held9cf1dd22018-07-31 14:52:40 +020063 * Bit 18-19 : number of queued commands - 1
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010064 */
65
Felix Held9cf1dd22018-07-31 14:52:40 +020066#define RUN_QUEUE_4284(x) ((((x) - 1) << 18) | 1) // 0 <= x < 4
67
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010068static void sfence(void)
69{
70 asm volatile ("sfence");
71}
72
73static void toggle_io_reset(void) {
74 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020075 u32 r32 = MCHBAR32(0x5030);
76 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010077 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020078 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010079 udelay(1);
80}
81
82static u32 get_XOVER_CLK(u8 rankmap)
83{
84 return rankmap << 24;
85}
86
87static u32 get_XOVER_CMD(u8 rankmap)
88{
89 u32 reg;
90
91 // enable xover cmd
92 reg = 0x4000;
93
94 // enable xover ctl
95 if (rankmap & 0x3)
96 reg |= 0x20000;
97
98 if (rankmap & 0xc)
99 reg |= 0x4000000;
100
101 return reg;
102}
103
104/* CAS write latency. To be programmed in MR2.
105 * See DDR3 SPEC for MR2 documentation. */
106u8 get_CWL(u32 tCK)
107{
108 /* Get CWL based on tCK using the following rule: */
109 switch (tCK) {
110 case TCK_1333MHZ:
111 return 12;
112 case TCK_1200MHZ:
113 case TCK_1100MHZ:
114 return 11;
115 case TCK_1066MHZ:
116 case TCK_1000MHZ:
117 return 10;
118 case TCK_933MHZ:
119 case TCK_900MHZ:
120 return 9;
121 case TCK_800MHZ:
122 case TCK_700MHZ:
123 return 8;
124 case TCK_666MHZ:
125 return 7;
126 case TCK_533MHZ:
127 return 6;
128 default:
129 return 5;
130 }
131}
132
133void dram_find_common_params(ramctr_timing *ctrl)
134{
135 size_t valid_dimms;
136 int channel, slot;
137 dimm_info *dimms = &ctrl->info;
138
139 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
140 valid_dimms = 0;
141 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
142 const dimm_attr *dimm = &dimms->dimm[channel][slot];
143 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
144 continue;
145 valid_dimms++;
146
147 /* Find all possible CAS combinations */
148 ctrl->cas_supported &= dimm->cas_supported;
149
150 /* Find the smallest common latencies supported by all DIMMs */
151 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
152 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
153 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
154 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
155 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
156 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
157 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
158 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
159 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
160 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
161 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300162 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
163 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100164 }
165
166 if (!ctrl->cas_supported)
167 die("Unsupported DIMM combination. "
168 "DIMMS do not support common CAS latency");
169 if (!valid_dimms)
170 die("No valid DIMMs found");
171}
172
173void dram_xover(ramctr_timing * ctrl)
174{
175 u32 reg;
176 int channel;
177
178 FOR_ALL_CHANNELS {
179 // enable xover clk
180 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
181 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
182 reg);
183 MCHBAR32(channel * 0x100 + 0xc14) = reg;
184
185 // enable xover ctl & xover cmd
186 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
187 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
188 reg);
189 MCHBAR32(0x100 * channel + 0x320c) = reg;
190 }
191}
192
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100193static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100194{
Iru Cai89af71c2018-08-16 16:46:27 +0800195 u32 addr, cpu, stretch;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100196
197 stretch = ctrl->ref_card_offset[channel];
198 /* ODT stretch: Delay ODT signal by stretch value.
199 * Useful for multi DIMM setups on the same channel. */
Subrata Banik53b08c32018-12-10 14:11:35 +0530200 cpu = cpu_get_cpuid();
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100201 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
202 if (stretch == 2)
203 stretch = 3;
Iru Cai89af71c2018-08-16 16:46:27 +0800204 addr = 0x401c + 0x400 * channel;
205 MCHBAR32_AND_OR(addr, 0xffffc3ff,
Felix Held9fe248f2018-07-31 20:59:45 +0200206 (stretch << 12) | (stretch << 10));
Iru Cai89af71c2018-08-16 16:46:27 +0800207 printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr,
208 MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100209 } else {
210 // OTHP
Iru Cai89af71c2018-08-16 16:46:27 +0800211 addr = 0x400c + 0x400 * channel;
212 MCHBAR32_AND_OR(addr, 0xfff0ffff,
Felix Held9fe248f2018-07-31 20:59:45 +0200213 (stretch << 16) | (stretch << 18));
Iru Cai89af71c2018-08-16 16:46:27 +0800214 printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100215 }
216}
217
218void dram_timing_regs(ramctr_timing *ctrl)
219{
220 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100221 int channel;
222
223 FOR_ALL_CHANNELS {
224 // DBP
225 reg = 0;
226 reg |= ctrl->tRCD;
227 reg |= (ctrl->tRP << 4);
228 reg |= (ctrl->CAS << 8);
229 reg |= (ctrl->CWL << 12);
230 reg |= (ctrl->tRAS << 16);
231 printram("DBP [%x] = %x\n", 0x400 * channel + 0x4000, reg);
232 MCHBAR32(0x400 * channel + 0x4000) = reg;
233
234 // RAP
235 reg = 0;
236 reg |= ctrl->tRRD;
237 reg |= (ctrl->tRTP << 4);
238 reg |= (ctrl->tCKE << 8);
239 reg |= (ctrl->tWTR << 12);
240 reg |= (ctrl->tFAW << 16);
241 reg |= (ctrl->tWR << 24);
242 reg |= (3 << 30);
243 printram("RAP [%x] = %x\n", 0x400 * channel + 0x4004, reg);
244 MCHBAR32(0x400 * channel + 0x4004) = reg;
245
246 // OTHP
247 addr = 0x400 * channel + 0x400c;
248 reg = 0;
249 reg |= ctrl->tXPDLL;
250 reg |= (ctrl->tXP << 5);
251 reg |= (ctrl->tAONPD << 8);
252 reg |= 0xa0000;
253 printram("OTHP [%x] = %x\n", addr, reg);
254 MCHBAR32(addr) = reg;
255
256 MCHBAR32(0x400 * channel + 0x4014) = 0;
257
Felix Held9fe248f2018-07-31 20:59:45 +0200258 MCHBAR32_OR(addr, 0x00020000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100259
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100260 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100261
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100262 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200263 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100264 * The tREFIx9 field should be programmed to minimum of
265 * 8.9*tREFI (to allow for possible delays from ZQ or
266 * isoc) and tRASmax (70us) divided by 1024.
267 */
268 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
269
270 reg = ((ctrl->tREFI & 0xffff) << 0) |
271 ((ctrl->tRFC & 0x1ff) << 16) |
272 (((val32 / 1024) & 0x7f) << 25);
273 printram("REFI [%x] = %x\n", 0x400 * channel + 0x4298, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100274 MCHBAR32(0x400 * channel + 0x4298) = reg;
275
Felix Held9fe248f2018-07-31 20:59:45 +0200276 MCHBAR32_OR(0x400 * channel + 0x4294, 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100277
278 // SRFTP
279 reg = 0;
280 val32 = tDLLK;
281 reg = (reg & ~0xfff) | val32;
282 val32 = ctrl->tXSOffset;
283 reg = (reg & ~0xf000) | (val32 << 12);
284 val32 = tDLLK - ctrl->tXSOffset;
285 reg = (reg & ~0x3ff0000) | (val32 << 16);
286 val32 = ctrl->tMOD - 8;
287 reg = (reg & ~0xf0000000) | (val32 << 28);
288 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
289 reg);
290 MCHBAR32(0x400 * channel + 0x42a4) = reg;
291 }
292}
293
294void dram_dimm_mapping(ramctr_timing *ctrl)
295{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100296 int channel;
297 dimm_info *info = &ctrl->info;
298
299 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200300 dimm_attr *dimmA, *dimmB;
301 u32 reg = 0;
302
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100303 if (info->dimm[channel][0].size_mb >=
304 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100305 dimmA = &info->dimm[channel][0];
306 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200307 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100308 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100309 dimmA = &info->dimm[channel][1];
310 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200311 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100312 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100313
Nico Huberac4f2162017-10-01 18:14:43 +0200314 if (dimmA && (dimmA->ranks > 0)) {
315 reg |= dimmA->size_mb / 256;
316 reg |= (dimmA->ranks - 1) << 17;
317 reg |= (dimmA->width / 8 - 1) << 19;
318 }
319
320 if (dimmB && (dimmB->ranks > 0)) {
321 reg |= (dimmB->size_mb / 256) << 8;
322 reg |= (dimmB->ranks - 1) << 18;
323 reg |= (dimmB->width / 8 - 1) << 20;
324 }
325
326 reg |= 1 << 21; /* rank interleave */
327 reg |= 1 << 22; /* enhanced interleave */
328
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100329 if ((dimmA && (dimmA->ranks > 0))
330 || (dimmB && (dimmB->ranks > 0))) {
331 ctrl->mad_dimm[channel] = reg;
332 } else {
333 ctrl->mad_dimm[channel] = 0;
334 }
335 }
336}
337
338void dram_dimm_set_mapping(ramctr_timing * ctrl)
339{
340 int channel;
341 FOR_ALL_CHANNELS {
342 MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
343 }
344}
345
346void dram_zones(ramctr_timing * ctrl, int training)
347{
348 u32 reg, ch0size, ch1size;
349 u8 val;
350 reg = 0;
351 val = 0;
352 if (training) {
353 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
354 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
355 } else {
356 ch0size = ctrl->channel_size_mb[0];
357 ch1size = ctrl->channel_size_mb[1];
358 }
359
360 if (ch0size >= ch1size) {
361 reg = MCHBAR32(0x5014);
362 val = ch1size / 256;
363 reg = (reg & ~0xff000000) | val << 24;
364 reg = (reg & ~0xff0000) | (2 * val) << 16;
365 MCHBAR32(0x5014) = reg;
366 MCHBAR32(0x5000) = 0x24;
367 } else {
368 reg = MCHBAR32(0x5014);
369 val = ch0size / 256;
370 reg = (reg & ~0xff000000) | val << 24;
371 reg = (reg & ~0xff0000) | (2 * val) << 16;
372 MCHBAR32(0x5014) = reg;
373 MCHBAR32(0x5000) = 0x21;
374 }
375}
376
377#define HOST_BRIDGE PCI_DEVFN(0, 0)
378#define DEFAULT_TCK TCK_800MHZ
379
380unsigned int get_mem_min_tck(void)
381{
382 u32 reg32;
383 u8 rev;
384 const struct device *dev;
385 const struct northbridge_intel_sandybridge_config *cfg = NULL;
386
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300387 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100388 if (dev)
389 cfg = dev->chip_info;
390
391 /* If this is zero, it just means devicetree.cb didn't set it */
392 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Patrick Rudolphb794a692017-08-08 13:13:51 +0200393 if (IS_ENABLED(CONFIG_NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
394 return TCK_1333MHZ;
395
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100396 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
397
398 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
399 /* read Capabilities A Register DMFC bits */
400 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
401 reg32 &= 0x7;
402
403 switch (reg32) {
404 case 7: return TCK_533MHZ;
405 case 6: return TCK_666MHZ;
406 case 5: return TCK_800MHZ;
407 /* reserved: */
408 default:
409 break;
410 }
411 } else {
412 /* read Capabilities B Register DMFC bits */
413 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
414 reg32 = (reg32 >> 4) & 0x7;
415
416 switch (reg32) {
417 case 7: return TCK_533MHZ;
418 case 6: return TCK_666MHZ;
419 case 5: return TCK_800MHZ;
420 case 4: return TCK_933MHZ;
421 case 3: return TCK_1066MHZ;
422 case 2: return TCK_1200MHZ;
423 case 1: return TCK_1333MHZ;
424 /* reserved: */
425 default:
426 break;
427 }
428 }
429 return DEFAULT_TCK;
430 } else {
431 if (cfg->max_mem_clock_mhz >= 1066)
432 return TCK_1066MHZ;
433 else if (cfg->max_mem_clock_mhz >= 933)
434 return TCK_933MHZ;
435 else if (cfg->max_mem_clock_mhz >= 800)
436 return TCK_800MHZ;
437 else if (cfg->max_mem_clock_mhz >= 666)
438 return TCK_666MHZ;
439 else if (cfg->max_mem_clock_mhz >= 533)
440 return TCK_533MHZ;
441 else
442 return TCK_400MHZ;
443 }
444}
445
446#define DEFAULT_PCI_MMIO_SIZE 2048
447
448static unsigned int get_mmio_size(void)
449{
450 const struct device *dev;
451 const struct northbridge_intel_sandybridge_config *cfg = NULL;
452
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300453 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100454 if (dev)
455 cfg = dev->chip_info;
456
457 /* If this is zero, it just means devicetree.cb didn't set it */
458 if (!cfg || cfg->pci_mmio_size == 0)
459 return DEFAULT_PCI_MMIO_SIZE;
460 else
461 return cfg->pci_mmio_size;
462}
463
464void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
465{
466 u32 reg, val, reclaim;
467 u32 tom, gfxstolen, gttsize;
468 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
469 tsegbase, mestolenbase;
470 size_t tsegbasedelta, remapbase, remaplimit;
471 uint16_t ggc;
472
473 mmiosize = get_mmio_size();
474
475 ggc = pci_read_config16(NORTHBRIDGE, GGC);
476 if (!(ggc & 2)) {
477 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
478 gttsize = ((ggc >> 8) & 0x3);
479 } else {
480 gfxstolen = 0;
481 gttsize = 0;
482 }
483
484 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
485
486 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
487
488 mestolenbase = tom - me_uma_size;
489
490 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
491 tom - me_uma_size);
492 gfxstolenbase = toludbase - gfxstolen;
493 gttbase = gfxstolenbase - gttsize;
494
495 tsegbase = gttbase - tsegsize;
496
497 // Round tsegbase down to nearest address aligned to tsegsize
498 tsegbasedelta = tsegbase & (tsegsize - 1);
499 tsegbase &= ~(tsegsize - 1);
500
501 gttbase -= tsegbasedelta;
502 gfxstolenbase -= tsegbasedelta;
503 toludbase -= tsegbasedelta;
504
505 // Test if it is possible to reclaim a hole in the RAM addressing
506 if (tom - me_uma_size > toludbase) {
507 // Reclaim is possible
508 reclaim = 1;
509 remapbase = MAX(4096, tom - me_uma_size);
510 remaplimit =
511 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
512 touudbase = remaplimit + 1;
513 } else {
514 // Reclaim not possible
515 reclaim = 0;
516 touudbase = tom - me_uma_size;
517 }
518
519 // Update memory map in pci-e configuration space
520 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
521
522 // TOM (top of memory)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300523 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100524 val = tom & 0xfff;
525 reg = (reg & ~0xfff00000) | (val << 20);
526 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300527 pci_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100528
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300529 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100530 val = tom & 0xfffff000;
531 reg = (reg & ~0x000fffff) | (val >> 12);
532 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300533 pci_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100534
535 // TOLUD (top of low used dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300536 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xbc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100537 val = toludbase & 0xfff;
538 reg = (reg & ~0xfff00000) | (val << 20);
539 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xbc, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300540 pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100541
542 // TOUUD LSB (top of upper usable dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300543 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100544 val = touudbase & 0xfff;
545 reg = (reg & ~0xfff00000) | (val << 20);
546 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300547 pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100548
549 // TOUUD MSB
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300550 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xac);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100551 val = touudbase & 0xfffff000;
552 reg = (reg & ~0x000fffff) | (val >> 12);
553 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xac, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300554 pci_write_config32(PCI_DEV(0, 0, 0), 0xac, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100555
556 if (reclaim) {
557 // REMAP BASE
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300558 pci_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20);
559 pci_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100560
561 // REMAP LIMIT
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300562 pci_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20);
563 pci_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100564 }
565 // TSEG
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300566 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100567 val = tsegbase & 0xfff;
568 reg = (reg & ~0xfff00000) | (val << 20);
569 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300570 pci_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100571
572 // GFX stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300573 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100574 val = gfxstolenbase & 0xfff;
575 reg = (reg & ~0xfff00000) | (val << 20);
576 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300577 pci_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100578
579 // GTT stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300580 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100581 val = gttbase & 0xfff;
582 reg = (reg & ~0xfff00000) | (val << 20);
583 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300584 pci_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100585
586 if (me_uma_size) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300587 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x7c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100588 val = (0x80000 - me_uma_size) & 0xfffff000;
589 reg = (reg & ~0x000fffff) | (val >> 12);
590 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x7c, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300591 pci_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100592
593 // ME base
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300594 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x70);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100595 val = mestolenbase & 0xfff;
596 reg = (reg & ~0xfff00000) | (val << 20);
597 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x70, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300598 pci_write_config32(PCI_DEV(0, 0, 0), 0x70, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100599
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300600 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x74);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100601 val = mestolenbase & 0xfffff000;
602 reg = (reg & ~0x000fffff) | (val >> 12);
603 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x74, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300604 pci_write_config32(PCI_DEV(0, 0, 0), 0x74, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100605
606 // ME mask
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300607 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x78);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100608 val = (0x80000 - me_uma_size) & 0xfff;
609 reg = (reg & ~0xfff00000) | (val << 20);
610 reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem
611
612 reg = (reg & ~0x800) | (1 << 11); // set ME memory enable
613 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x78, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300614 pci_write_config32(PCI_DEV(0, 0, 0), 0x78, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100615 }
616}
617
618static void wait_428c(int channel)
619{
620 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200621 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100622 return;
623 }
624}
625
626static void write_reset(ramctr_timing * ctrl)
627{
628 int channel, slotrank;
629
630 /* choose a populated channel. */
631 channel = (ctrl->rankmap[0]) ? 0 : 1;
632
633 wait_428c(channel);
634
635 /* choose a populated rank. */
636 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
637
638 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200639 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
640 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200641 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200642 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100643
Felix Held9cf1dd22018-07-31 14:52:40 +0200644 // execute command queue - why is bit 22 set here?!
645 MCHBAR32(0x4284 + 0x400 * channel) = (1 << 22) | RUN_QUEUE_4284(1);
646
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100647 wait_428c(channel);
648}
649
650void dram_jedecreset(ramctr_timing * ctrl)
651{
Felix Held9fe248f2018-07-31 20:59:45 +0200652 u32 reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100653 int channel;
654
655 while (!(MCHBAR32(0x5084) & 0x10000));
656 do {
657 reg = MCHBAR32(0x428c);
658 } while ((reg & 0x14) == 0);
659
660 // Set state of memory controller
661 reg = 0x112;
662 MCHBAR32(0x5030) = reg;
663 MCHBAR32(0x4ea0) = 0;
664 reg |= 2; //ddr reset
665 MCHBAR32(0x5030) = reg;
666
667 // Assert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200668 MCHBAR32_AND(0x5030, ~0x2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100669
670 // Wait 200us
671 udelay(200);
672
673 // Deassert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200674 MCHBAR32_OR(0x5030, 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100675
676 // Wait 500us
677 udelay(500);
678
679 // Enable DCLK
Felix Held9fe248f2018-07-31 20:59:45 +0200680 MCHBAR32_OR(0x5030, 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100681
682 // XXX Wait 20ns
683 udelay(1);
684
685 FOR_ALL_CHANNELS {
686 // Set valid rank CKE
Felix Held9fe248f2018-07-31 20:59:45 +0200687 reg = ctrl->rankmap[channel];
688 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100689
690 // Wait 10ns for ranks to settle
691 //udelay(0.01);
692
693 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
Felix Held9fe248f2018-07-31 20:59:45 +0200694 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100695
696 // Write reset using a NOP
697 write_reset(ctrl);
698 }
699}
700
701static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
702{
703 /* Get ODT based on rankmap: */
704 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
705 + ((ctrl->rankmap[channel] >> 2) & 1);
706
707 if (dimms_per_ch == 1) {
708 return (const odtmap){60, 60};
709 } else {
710 return (const odtmap){120, 30};
711 }
712}
713
714static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
715 int reg, u32 val)
716{
717 wait_428c(channel);
718
719 if (ctrl->rank_mirror[channel][slotrank]) {
720 /* DDR3 Rank1 Address mirror
721 * swap the following pins:
722 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
723 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
724 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
725 | ((val & 0xa8) << 1);
726 }
727
728 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200729 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
730 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
731 MCHBAR32(0x4200 + 0x400 * channel) =
732 (slotrank << 24) | (reg << 20) | val | 0x60000;
733 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100734
735 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200736 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
737 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
738 MCHBAR32(0x4204 + 0x400 * channel) =
739 (slotrank << 24) | (reg << 20) | val | 0x60000;
740 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100741
742 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200743 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
744 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
745 MCHBAR32(0x4208 + 0x400 * channel) =
746 (slotrank << 24) | (reg << 20) | val | 0x60000;
747 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200748
749 // execute command queue
750 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100751}
752
753static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
754{
755 u16 mr0reg, mch_cas, mch_wr;
756 static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 };
Patrick Rudolph74203de2017-11-20 11:57:01 +0100757 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100758
759 /* DLL Reset - self clearing - set after CLK frequency has been changed */
760 mr0reg = 0x100;
761
762 // Convert CAS to MCH register friendly
763 if (ctrl->CAS < 12) {
764 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
765 } else {
766 mch_cas = (u16) (ctrl->CAS - 12);
767 mch_cas = ((mch_cas << 1) | 0x1);
768 }
769
770 // Convert tWR to MCH register friendly
771 mch_wr = mch_wr_t[ctrl->tWR - 5];
772
773 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
774 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
775 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
776
777 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100778 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100779 return mr0reg;
780}
781
782static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
783{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200784 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100785}
786
787static u32 encode_odt(u32 odt)
788{
789 switch (odt) {
790 case 30:
791 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
792 case 60:
793 return (1 << 2); // RZQ/4
794 case 120:
795 return (1 << 6); // RZQ/2
796 default:
797 case 0:
798 return 0;
799 }
800}
801
802static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
803{
804 odtmap odt;
805 u32 mr1reg;
806
807 odt = get_ODT(ctrl, rank, channel);
808 mr1reg = 0x2;
809
810 mr1reg |= encode_odt(odt.rttnom);
811
812 return mr1reg;
813}
814
815static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
816{
817 u16 mr1reg;
818
819 mr1reg = make_mr1(ctrl, rank, channel);
820
821 write_mrreg(ctrl, channel, rank, 1, mr1reg);
822}
823
824static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
825{
826 u16 pasr, cwl, mr2reg;
827 odtmap odt;
828 int srt;
829
830 pasr = 0;
831 cwl = ctrl->CWL - 5;
832 odt = get_ODT(ctrl, rank, channel);
833
834 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
835
836 mr2reg = 0;
837 mr2reg = (mr2reg & ~0x7) | pasr;
838 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
839 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
840 mr2reg = (mr2reg & ~0x80) | (srt << 7);
841 mr2reg |= (odt.rttwr / 60) << 9;
842
843 write_mrreg(ctrl, channel, rank, 2, mr2reg);
844}
845
846static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
847{
848 write_mrreg(ctrl, channel, rank, 3, 0);
849}
850
851void dram_mrscommands(ramctr_timing * ctrl)
852{
853 u8 slotrank;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100854 int channel;
855
856 FOR_ALL_POPULATED_CHANNELS {
857 FOR_ALL_POPULATED_RANKS {
858 // MR2
859 dram_mr2(ctrl, slotrank, channel);
860
861 // MR3
862 dram_mr3(ctrl, slotrank, channel);
863
864 // MR1
865 dram_mr1(ctrl, slotrank, channel);
866
867 // MR0
868 dram_mr0(ctrl, slotrank, channel);
869 }
870 }
871
872 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200873 MCHBAR32(0x4e20) = 0x7;
874 MCHBAR32(0x4e30) = 0xf1001;
875 MCHBAR32(0x4e00) = 0x60002;
876 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100877
878 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200879 MCHBAR32(0x4e24) = 0x1f003;
880 MCHBAR32(0x4e34) = 0x1901001;
881 MCHBAR32(0x4e04) = 0x60400;
882 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100883
Felix Held9cf1dd22018-07-31 14:52:40 +0200884 // execute command queue on all channels? Why isn't bit 0 set here?
Felix Held2bb3cdf2018-07-28 00:23:59 +0200885 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100886
887 // Drain
888 FOR_ALL_CHANNELS {
889 // Wait for ref drained
890 wait_428c(channel);
891 }
892
893 // Refresh enable
Felix Held9fe248f2018-07-31 20:59:45 +0200894 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100895
896 FOR_ALL_POPULATED_CHANNELS {
Felix Held9fe248f2018-07-31 20:59:45 +0200897 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100898
899 wait_428c(channel);
900
901 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
902
903 // Drain
904 wait_428c(channel);
905
906 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200907 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
908 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
909 MCHBAR32(0x4200 + 0x400 * channel) =
910 (slotrank << 24) | 0x60000;
911 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200912
913 // execute command queue
914 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100915
916 // Drain
917 wait_428c(channel);
918 }
919}
920
921static const u32 lane_registers[] = {
922 0x0000, 0x0200, 0x0400, 0x0600,
923 0x1000, 0x1200, 0x1400, 0x1600,
924 0x0800
925};
926
927void program_timings(ramctr_timing * ctrl, int channel)
928{
929 u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028;
930 int lane;
931 int slotrank, slot;
932 int full_shift = 0;
933 u16 slot320c[NUM_SLOTS];
934
935 FOR_ALL_POPULATED_RANKS {
936 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
937 full_shift = -ctrl->timings[channel][slotrank].val_320c;
938 }
939
940 for (slot = 0; slot < NUM_SLOTS; slot++)
941 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
942 case 0:
943 default:
944 slot320c[slot] = 0x7f;
945 break;
946 case 1:
947 slot320c[slot] =
948 ctrl->timings[channel][2 * slot + 0].val_320c +
949 full_shift;
950 break;
951 case 2:
952 slot320c[slot] =
953 ctrl->timings[channel][2 * slot + 1].val_320c +
954 full_shift;
955 break;
956 case 3:
957 slot320c[slot] =
958 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200959 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100960 full_shift;
961 break;
962 }
963
964 /* enable CMD XOVER */
965 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
966 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
967 reg32 |= (slot320c[1] & 0x7f) << 18;
968 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
969
970 MCHBAR32(0x320c + 0x100 * channel) = reg32;
971
972 /* enable CLK XOVER */
973 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
974 reg_c18 = 0;
975
976 FOR_ALL_POPULATED_RANKS {
977 int shift =
978 ctrl->timings[channel][slotrank].val_320c + full_shift;
979 int offset_val_c14;
980 if (shift < 0)
981 shift = 0;
982 offset_val_c14 = ctrl->reg_c14_offset + shift;
983 /* set CLK phase shift */
984 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
985 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
986 }
987
988 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
989 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
990
991 reg_4028 = MCHBAR32(0x4028 + 0x400 * channel);
992 reg_4028 &= 0xffff0000;
993
994 reg_4024 = 0;
995
996 FOR_ALL_POPULATED_RANKS {
997 int post_timA_min_high = 7, post_timA_max_high = 0;
998 int pre_timA_min_high = 7, pre_timA_max_high = 0;
999 int shift_402x = 0;
1000 int shift =
1001 ctrl->timings[channel][slotrank].val_320c + full_shift;
1002
1003 if (shift < 0)
1004 shift = 0;
1005
1006 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001007 post_timA_min_high = MIN(post_timA_min_high,
1008 (ctrl->timings[channel][slotrank].lanes[lane].
1009 timA + shift) >> 6);
1010 pre_timA_min_high = MIN(pre_timA_min_high,
1011 ctrl->timings[channel][slotrank].lanes[lane].
1012 timA >> 6);
1013 post_timA_max_high = MAX(post_timA_max_high,
1014 (ctrl->timings[channel][slotrank].lanes[lane].
1015 timA + shift) >> 6);
1016 pre_timA_max_high = MAX(pre_timA_max_high,
1017 ctrl->timings[channel][slotrank].lanes[lane].
1018 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001019 }
1020
1021 if (pre_timA_max_high - pre_timA_min_high <
1022 post_timA_max_high - post_timA_min_high)
1023 shift_402x = +1;
1024 else if (pre_timA_max_high - pre_timA_min_high >
1025 post_timA_max_high - post_timA_min_high)
1026 shift_402x = -1;
1027
1028 reg_4028 |=
1029 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1030 post_timA_min_high) << (4 * slotrank);
1031 reg_4024 |=
1032 (ctrl->timings[channel][slotrank].val_4024 +
1033 shift_402x) << (8 * slotrank);
1034
1035 FOR_ALL_LANES {
1036 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1037 4 * slotrank)
1038 =
1039 (((ctrl->timings[channel][slotrank].lanes[lane].
1040 timA + shift) & 0x3f)
1041 |
1042 ((ctrl->timings[channel][slotrank].lanes[lane].
1043 rising + shift) << 8)
1044 |
1045 (((ctrl->timings[channel][slotrank].lanes[lane].
1046 timA + shift -
1047 (post_timA_min_high << 6)) & 0x1c0) << 10)
1048 | ((ctrl->timings[channel][slotrank].lanes[lane].
1049 falling + shift) << 20));
1050
1051 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1052 4 * slotrank)
1053 =
1054 (((ctrl->timings[channel][slotrank].lanes[lane].
1055 timC + shift) & 0x3f)
1056 |
1057 (((ctrl->timings[channel][slotrank].lanes[lane].
1058 timB + shift) & 0x3f) << 8)
1059 |
1060 (((ctrl->timings[channel][slotrank].lanes[lane].
1061 timB + shift) & 0x1c0) << 9)
1062 |
1063 (((ctrl->timings[channel][slotrank].lanes[lane].
1064 timC + shift) & 0x40) << 13));
1065 }
1066 }
1067 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
1068 MCHBAR32(0x4028 + 0x400 * channel) = reg_4028;
1069}
1070
1071static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1072{
1073 wait_428c(channel);
1074
1075 /* DRAM command MRS
1076 * write MR3 MPR enable
1077 * in this mode only RD and RDA are allowed
1078 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001079 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1080 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1081 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1082 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001083
1084 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001085 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1086 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1087 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1088 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001089
1090 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001091 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1092 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1093 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1094 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001095
1096 /* DRAM command MRS
1097 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001098 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1099 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1100 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1101 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001102
Felix Held9cf1dd22018-07-31 14:52:40 +02001103 // execute command queue
1104 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001105
1106 wait_428c(channel);
1107}
1108
1109static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1110 int lane)
1111{
1112 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001113 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001114 ((timA / 32) & 1) * 4)
1115 >> (timA % 32)) & 1);
1116}
1117
1118struct run {
1119 int middle;
1120 int end;
1121 int start;
1122 int all;
1123 int length;
1124};
1125
1126static struct run get_longest_zero_run(int *seq, int sz)
1127{
1128 int i, ls;
1129 int bl = 0, bs = 0;
1130 struct run ret;
1131
1132 ls = 0;
1133 for (i = 0; i < 2 * sz; i++)
1134 if (seq[i % sz]) {
1135 if (i - ls > bl) {
1136 bl = i - ls;
1137 bs = ls;
1138 }
1139 ls = i + 1;
1140 }
1141 if (bl == 0) {
1142 ret.middle = sz / 2;
1143 ret.start = 0;
1144 ret.end = sz;
1145 ret.all = 1;
1146 return ret;
1147 }
1148
1149 ret.start = bs % sz;
1150 ret.end = (bs + bl - 1) % sz;
1151 ret.middle = (bs + (bl - 1) / 2) % sz;
1152 ret.length = bl;
1153 ret.all = 0;
1154
1155 return ret;
1156}
1157
1158static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1159 int slotrank, int *upperA)
1160{
1161 int timA;
1162 int statistics[NUM_LANES][128];
1163 int lane;
1164
1165 for (timA = 0; timA < 128; timA++) {
1166 FOR_ALL_LANES {
1167 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1168 }
1169 program_timings(ctrl, channel);
1170
1171 test_timA(ctrl, channel, slotrank);
1172
1173 FOR_ALL_LANES {
1174 statistics[lane][timA] =
1175 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001176 }
1177 }
1178 FOR_ALL_LANES {
1179 struct run rn = get_longest_zero_run(statistics[lane], 128);
1180 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1181 upperA[lane] = rn.end;
1182 if (upperA[lane] < rn.middle)
1183 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001184 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001185 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001186 }
1187}
1188
1189static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1190 int *upperA)
1191{
1192 int timA_delta;
1193 int statistics[NUM_LANES][51];
1194 int lane, i;
1195
1196 memset(statistics, 0, sizeof(statistics));
1197
1198 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1199 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1200 timA = upperA[lane] + timA_delta + 0x40;
1201 program_timings(ctrl, channel);
1202
1203 for (i = 0; i < 100; i++) {
1204 test_timA(ctrl, channel, slotrank);
1205 FOR_ALL_LANES {
1206 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001207 does_lane_work(ctrl, channel, slotrank,
1208 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001209 }
1210 }
1211 }
1212 FOR_ALL_LANES {
1213 int last_zero, first_all;
1214
1215 for (last_zero = -25; last_zero <= 25; last_zero++)
1216 if (statistics[lane][last_zero + 25])
1217 break;
1218 last_zero--;
1219 for (first_all = -25; first_all <= 25; first_all++)
1220 if (statistics[lane][first_all + 25] == 100)
1221 break;
1222
1223 printram("lane %d: %d, %d\n", lane, last_zero,
1224 first_all);
1225
1226 ctrl->timings[channel][slotrank].lanes[lane].timA =
1227 (last_zero + first_all) / 2 + upperA[lane];
1228 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1229 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1230 }
1231}
1232
1233static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1234 int *upperA)
1235{
1236 int works[NUM_LANES];
1237 int lane;
1238 while (1) {
1239 int all_works = 1, some_works = 0;
1240 program_timings(ctrl, channel);
1241 test_timA(ctrl, channel, slotrank);
1242 FOR_ALL_LANES {
1243 works[lane] =
1244 !does_lane_work(ctrl, channel, slotrank, lane);
1245 if (works[lane])
1246 some_works = 1;
1247 else
1248 all_works = 0;
1249 }
1250 if (all_works)
1251 return 0;
1252 if (!some_works) {
1253 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1254 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1255 channel, slotrank);
1256 return MAKE_ERR;
1257 }
1258 ctrl->timings[channel][slotrank].val_4024 -= 2;
1259 printram("4024 -= 2;\n");
1260 continue;
1261 }
1262 ctrl->timings[channel][slotrank].val_4028 += 2;
1263 printram("4028 += 2;\n");
1264 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1265 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1266 channel, slotrank);
1267 return MAKE_ERR;
1268 }
1269 FOR_ALL_LANES if (works[lane]) {
1270 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1271 128;
1272 upperA[lane] += 128;
1273 printram("increment %d, %d, %d\n", channel,
1274 slotrank, lane);
1275 }
1276 }
1277 return 0;
1278}
1279
1280struct timA_minmax {
1281 int timA_min_high, timA_max_high;
1282};
1283
1284static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1285 struct timA_minmax *mnmx)
1286{
1287 int lane;
1288 mnmx->timA_min_high = 7;
1289 mnmx->timA_max_high = 0;
1290
1291 FOR_ALL_LANES {
1292 if (mnmx->timA_min_high >
1293 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1294 mnmx->timA_min_high =
1295 (ctrl->timings[channel][slotrank].lanes[lane].
1296 timA >> 6);
1297 if (mnmx->timA_max_high <
1298 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1299 mnmx->timA_max_high =
1300 (ctrl->timings[channel][slotrank].lanes[lane].
1301 timA >> 6);
1302 }
1303}
1304
1305static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1306 struct timA_minmax *mnmx)
1307{
1308 struct timA_minmax post;
1309 int shift_402x = 0;
1310
1311 /* Get changed maxima. */
1312 pre_timA_change(ctrl, channel, slotrank, &post);
1313
1314 if (mnmx->timA_max_high - mnmx->timA_min_high <
1315 post.timA_max_high - post.timA_min_high)
1316 shift_402x = +1;
1317 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1318 post.timA_max_high - post.timA_min_high)
1319 shift_402x = -1;
1320 else
1321 shift_402x = 0;
1322
1323 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1324 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1325 printram("4024 += %d;\n", shift_402x);
1326 printram("4028 += %d;\n", shift_402x);
1327}
1328
1329/* Compensate the skew between DQS and DQs.
1330 * To ease PCB design a small skew between Data Strobe signals and
1331 * Data Signals is allowed.
1332 * The controller has to measure and compensate this skew for every byte-lane.
1333 * By delaying either all DQs signals or DQS signal, a full phase
1334 * shift can be introduced.
1335 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1336 *
1337 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1338 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1339 * The memory controller iterates over all possible values to do a full phase shift
1340 * and issues read commands.
1341 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1342 * 0xFF 0x00 0xFF ...
1343 * Once the controller has detected this pattern a bit in the result register is
1344 * set for the current phase shift.
1345 */
1346int read_training(ramctr_timing * ctrl)
1347{
1348 int channel, slotrank, lane;
1349 int err;
1350
1351 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1352 int all_high, some_high;
1353 int upperA[NUM_LANES];
1354 struct timA_minmax mnmx;
1355
Felix Held2bb3cdf2018-07-28 00:23:59 +02001356 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001357
Felix Held2bb3cdf2018-07-28 00:23:59 +02001358 /* DRAM command PREA */
1359 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1360 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1361 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1362 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001363
1364 // execute command queue
1365 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001366
Felix Held2bb3cdf2018-07-28 00:23:59 +02001367 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001368
Felix Held2bb3cdf2018-07-28 00:23:59 +02001369 ctrl->timings[channel][slotrank].val_4028 = 4;
1370 ctrl->timings[channel][slotrank].val_4024 = 55;
1371 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001372
Felix Held2bb3cdf2018-07-28 00:23:59 +02001373 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001374
Felix Held2bb3cdf2018-07-28 00:23:59 +02001375 all_high = 1;
1376 some_high = 0;
1377 FOR_ALL_LANES {
1378 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1379 0x40)
1380 some_high = 1;
1381 else
1382 all_high = 0;
1383 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001384
1385 if (all_high) {
1386 ctrl->timings[channel][slotrank].val_4028--;
1387 printram("4028--;\n");
1388 FOR_ALL_LANES {
1389 ctrl->timings[channel][slotrank].lanes[lane].
1390 timA -= 0x40;
1391 upperA[lane] -= 0x40;
1392
1393 }
1394 } else if (some_high) {
1395 ctrl->timings[channel][slotrank].val_4024++;
1396 ctrl->timings[channel][slotrank].val_4028++;
1397 printram("4024++;\n");
1398 printram("4028++;\n");
1399 }
1400
1401 program_timings(ctrl, channel);
1402
1403 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1404
1405 err = discover_402x(ctrl, channel, slotrank, upperA);
1406 if (err)
1407 return err;
1408
1409 post_timA_change(ctrl, channel, slotrank, &mnmx);
1410 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1411
1412 discover_timA_fine(ctrl, channel, slotrank, upperA);
1413
1414 post_timA_change(ctrl, channel, slotrank, &mnmx);
1415 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1416
1417 FOR_ALL_LANES {
1418 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1419 }
1420 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1421 printram("4028 -= %d;\n", mnmx.timA_min_high);
1422
1423 post_timA_change(ctrl, channel, slotrank, &mnmx);
1424
1425 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1426 ctrl->timings[channel][slotrank].val_4024,
1427 ctrl->timings[channel][slotrank].val_4028);
1428
1429 printram("final results:\n");
1430 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001431 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1432 lane,
1433 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001434
Felix Held2bb3cdf2018-07-28 00:23:59 +02001435 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001436
1437 toggle_io_reset();
1438 }
1439
1440 FOR_ALL_POPULATED_CHANNELS {
1441 program_timings(ctrl, channel);
1442 }
1443 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001444 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001445 }
1446 return 0;
1447}
1448
1449static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1450{
1451 int lane;
1452
1453 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001454 volatile u32 tmp;
1455 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
1456 tmp = MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001457 }
1458
1459 wait_428c(channel);
1460
1461 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001462 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1463 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001464 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001465 | 4 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001466 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001467 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001468
1469 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001470 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1471 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1472 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1473 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001474
1475 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001476 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1477 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1478 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1479 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001480
1481 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001482 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1483 MCHBAR32(0x423c + 0x400 * channel) =
1484 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1485 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1486 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001487
Felix Held9cf1dd22018-07-31 14:52:40 +02001488 // execute command queue
1489 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001490
1491 wait_428c(channel);
1492
1493 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001494 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1495 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1496 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1497 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001498
1499 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001500 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1501 MCHBAR32(0x4234 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001502 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001503 | 8 | (ctrl->CAS << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001504 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001505 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001506
1507 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001508 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1509 MCHBAR32(0x4238 + 0x400 * channel) =
1510 0x40011f4 | (max(ctrl->tRTP, 8) << 16);
1511 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1512 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001513
1514 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001515 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1516 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1517 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1518 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001519
1520 // execute command queue
1521 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1522
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001523 wait_428c(channel);
1524}
1525
1526static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1527{
1528 int timC;
1529 int statistics[NUM_LANES][MAX_TIMC + 1];
1530 int lane;
1531
1532 wait_428c(channel);
1533
1534 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001535 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1536 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
Felix Held9fe248f2018-07-31 20:59:45 +02001537 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001538 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001539
1540 // execute command queue
1541 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001542
1543 for (timC = 0; timC <= MAX_TIMC; timC++) {
1544 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1545 timC = timC;
1546 program_timings(ctrl, channel);
1547
1548 test_timC(ctrl, channel, slotrank);
1549
1550 FOR_ALL_LANES {
1551 statistics[lane][timC] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001552 MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001553 }
1554 }
1555 FOR_ALL_LANES {
1556 struct run rn =
1557 get_longest_zero_run(statistics[lane], MAX_TIMC + 1);
1558 ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
1559 if (rn.all) {
1560 printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
1561 channel, slotrank, lane);
1562 return MAKE_ERR;
1563 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001564 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001565 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001566 }
1567 return 0;
1568}
1569
1570static int get_precedening_channels(ramctr_timing * ctrl, int target_channel)
1571{
1572 int channel, ret = 0;
1573 FOR_ALL_POPULATED_CHANNELS if (channel < target_channel)
1574 ret++;
1575 return ret;
1576}
1577
1578static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b)
1579{
1580 unsigned j;
1581 unsigned channel_offset =
1582 get_precedening_channels(ctrl, channel) * 0x40;
1583 for (j = 0; j < 16; j++)
1584 write32((void *)(0x04000000 + channel_offset + 4 * j), j & 2 ? b : a);
1585 sfence();
1586}
1587
1588static int num_of_channels(const ramctr_timing * ctrl)
1589{
1590 int ret = 0;
1591 int channel;
1592 FOR_ALL_POPULATED_CHANNELS ret++;
1593 return ret;
1594}
1595
1596static void fill_pattern1(ramctr_timing * ctrl, int channel)
1597{
1598 unsigned j;
1599 unsigned channel_offset =
1600 get_precedening_channels(ctrl, channel) * 0x40;
1601 unsigned channel_step = 0x40 * num_of_channels(ctrl);
1602 for (j = 0; j < 16; j++)
1603 write32((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff);
1604 for (j = 0; j < 16; j++)
1605 write32((void *)(0x04000000 + channel_offset + channel_step + j * 4), 0);
1606 sfence();
1607}
1608
1609static void precharge(ramctr_timing * ctrl)
1610{
1611 int channel, slotrank, lane;
1612
1613 FOR_ALL_POPULATED_CHANNELS {
1614 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1615 ctrl->timings[channel][slotrank].lanes[lane].falling =
1616 16;
1617 ctrl->timings[channel][slotrank].lanes[lane].rising =
1618 16;
1619 }
1620
1621 program_timings(ctrl, channel);
1622
1623 FOR_ALL_POPULATED_RANKS {
1624 wait_428c(channel);
1625
1626 /* DRAM command MRS
1627 * write MR3 MPR enable
1628 * in this mode only RD and RDA are allowed
1629 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001630 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1631 MCHBAR32(0x4230 + 0x400 * channel) =
1632 0xc01 | (ctrl->tMOD << 16);
1633 MCHBAR32(0x4200 + 0x400 * channel) =
1634 (slotrank << 24) | 0x360004;
1635 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001636
1637 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001638 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1639 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1640 MCHBAR32(0x4204 + 0x400 * channel) =
1641 (slotrank << 24) | 0;
1642 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001643
1644 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001645 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1646 MCHBAR32(0x4238 + 0x400 * channel) =
1647 0x1001 | ((ctrl->CAS + 8) << 16);
1648 MCHBAR32(0x4208 + 0x400 * channel) =
1649 (slotrank << 24) | 0x60000;
1650 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001651
1652 /* DRAM command MRS
1653 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001654 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1655 MCHBAR32(0x423c + 0x400 * channel) =
1656 0xc01 | (ctrl->tMOD << 16);
1657 MCHBAR32(0x420c + 0x400 * channel) =
1658 (slotrank << 24) | 0x360000;
1659 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001660
1661 // execute command queue
1662 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001663
1664 wait_428c(channel);
1665 }
1666
1667 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1668 ctrl->timings[channel][slotrank].lanes[lane].falling =
1669 48;
1670 ctrl->timings[channel][slotrank].lanes[lane].rising =
1671 48;
1672 }
1673
1674 program_timings(ctrl, channel);
1675
1676 FOR_ALL_POPULATED_RANKS {
1677 wait_428c(channel);
1678 /* DRAM command MRS
1679 * write MR3 MPR enable
1680 * in this mode only RD and RDA are allowed
1681 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001682 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1683 MCHBAR32(0x4230 + 0x400 * channel) =
1684 0xc01 | (ctrl->tMOD << 16);
1685 MCHBAR32(0x4200 + 0x400 * channel) =
1686 (slotrank << 24) | 0x360004;
1687 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001688
1689 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001690 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1691 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1692 MCHBAR32(0x4204 + 0x400 * channel) =
1693 (slotrank << 24) | 0;
1694 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001695
1696 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001697 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1698 MCHBAR32(0x4238 + 0x400 * channel) =
1699 0x1001 | ((ctrl->CAS + 8) << 16);
1700 MCHBAR32(0x4208 + 0x400 * channel) =
1701 (slotrank << 24) | 0x60000;
1702 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001703
1704 /* DRAM command MRS
1705 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001706 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1707 MCHBAR32(0x423c + 0x400 * channel) =
1708 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001709 MCHBAR32(0x420c + 0x400 * channel) =
1710 (slotrank << 24) | 0x360000;
1711 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001712
Felix Held9cf1dd22018-07-31 14:52:40 +02001713 // execute command queue
1714 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1715
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001716 wait_428c(channel);
1717 }
1718 }
1719}
1720
1721static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1722{
1723 /* enable DQs on this slotrank */
1724 write_mrreg(ctrl, channel, slotrank, 1,
1725 0x80 | make_mr1(ctrl, slotrank, channel));
1726
1727 wait_428c(channel);
1728 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001729 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1730 MCHBAR32(0x4230 + 0x400 * channel) =
1731 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1732 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1733 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001734
1735 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001736 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1737 MCHBAR32(0x4234 + 0x400 * channel) =
1738 0x4000c01 | ((ctrl->CAS + 38) << 16);
1739 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1740 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001741
Felix Held9cf1dd22018-07-31 14:52:40 +02001742 // execute command queue
1743 MCHBAR32(0x400 * channel + 0x4284) = RUN_QUEUE_4284(2);
1744
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001745 wait_428c(channel);
1746
1747 /* disable DQs on this slotrank */
1748 write_mrreg(ctrl, channel, slotrank, 1,
1749 0x1080 | make_mr1(ctrl, slotrank, channel));
1750}
1751
1752static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1753{
1754 int timB;
1755 int statistics[NUM_LANES][128];
1756 int lane;
1757
Felix Held2bb3cdf2018-07-28 00:23:59 +02001758 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001759
1760 for (timB = 0; timB < 128; timB++) {
1761 FOR_ALL_LANES {
1762 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1763 }
1764 program_timings(ctrl, channel);
1765
1766 test_timB(ctrl, channel, slotrank);
1767
1768 FOR_ALL_LANES {
1769 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001770 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001771 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1772 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001773 }
1774 }
1775 FOR_ALL_LANES {
1776 struct run rn = get_longest_zero_run(statistics[lane], 128);
1777 /* timC is a direct function of timB's 6 LSBs.
1778 * Some tests increments the value of timB by a small value,
1779 * which might cause the 6bit value to overflow, if it's close
1780 * to 0x3F. Increment the value by a small offset if it's likely
1781 * to overflow, to make sure it won't overflow while running
1782 * tests and bricks the system due to a non matching timC.
1783 *
1784 * TODO: find out why some tests (edge write discovery)
1785 * increment timB. */
1786 if ((rn.start & 0x3F) == 0x3E)
1787 rn.start += 2;
1788 else if ((rn.start & 0x3F) == 0x3F)
1789 rn.start += 1;
1790 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1791 if (rn.all) {
1792 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1793 channel, slotrank, lane);
1794 return MAKE_ERR;
1795 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001796 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1797 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001798 }
1799 return 0;
1800}
1801
1802static int get_timB_high_adjust(u64 val)
1803{
1804 int i;
1805
1806 /* good */
1807 if (val == 0xffffffffffffffffLL)
1808 return 0;
1809
1810 if (val >= 0xf000000000000000LL) {
1811 /* needs negative adjustment */
1812 for (i = 0; i < 8; i++)
1813 if (val << (8 * (7 - i) + 4))
1814 return -i;
1815 } else {
1816 /* needs positive adjustment */
1817 for (i = 0; i < 8; i++)
1818 if (val >> (8 * (7 - i) + 4))
1819 return i;
1820 }
1821 return 8;
1822}
1823
1824static void adjust_high_timB(ramctr_timing * ctrl)
1825{
1826 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001827 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001828 FOR_ALL_POPULATED_CHANNELS {
1829 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001830 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001831 }
1832 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1833
Felix Held2bb3cdf2018-07-28 00:23:59 +02001834 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001835
1836 wait_428c(channel);
1837
1838 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001839 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1840 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1841 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1842 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001843
1844 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001845 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1846 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1847 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1848 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001849
1850 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001851 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1852 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1853 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1854 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001855
1856 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001857 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1858 MCHBAR32(0x423c + 0x400 * channel) =
1859 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1860 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1861 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001862
Felix Held9cf1dd22018-07-31 14:52:40 +02001863 // execute command queue
1864 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001865
1866 wait_428c(channel);
1867
1868 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001869 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1870 MCHBAR32(0x4230 + 0x400 * channel) =
1871 0xc01 | ((ctrl->tRP) << 16);
1872 MCHBAR32(0x4200 + 0x400 * channel) =
1873 (slotrank << 24) | 0x60400;
1874 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001875
1876 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001877 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1878 MCHBAR32(0x4234 + 0x400 * channel) =
1879 0xc01 | ((ctrl->tRCD) << 16);
1880 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1881 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001882
1883 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001884 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1885 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001886 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001887 ctrl->timings[channel][slotrank].val_4028) << 16);
1888 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1889 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001890
Felix Held9cf1dd22018-07-31 14:52:40 +02001891 // execute command queue
1892 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
1893
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001894 wait_428c(channel);
1895 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001896 u64 res = MCHBAR32(lane_registers[lane] +
1897 0x100 * channel + 4);
1898 res |= ((u64) MCHBAR32(lane_registers[lane] +
1899 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001900 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1901 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1902 get_timB_high_adjust(res) * 64;
1903
1904 printram("High adjust %d:%016llx\n", lane, res);
1905 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1906 slotrank, lane, old,
1907 ctrl->timings[channel][slotrank].lanes[lane].
1908 timB);
1909 }
1910 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001911 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001912}
1913
1914static void write_op(ramctr_timing * ctrl, int channel)
1915{
1916 int slotrank;
1917
1918 wait_428c(channel);
1919
1920 /* choose an existing rank. */
1921 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1922
1923 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001924 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1925 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001926 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001927 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001928
Felix Held9cf1dd22018-07-31 14:52:40 +02001929 // execute command queue
1930 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
1931
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001932 wait_428c(channel);
1933}
1934
1935/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1936 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1937 * the chips at different times with respect to command, address and
1938 * clock signals.
1939 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1940 * shift can be introduced.
1941 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1942 *
1943 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1944 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1945 * sampled value on the data lanes (DQs).
1946 */
1947int write_training(ramctr_timing * ctrl)
1948{
1949 int channel, slotrank, lane;
1950 int err;
1951
1952 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001953 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001954
1955 FOR_ALL_POPULATED_CHANNELS {
1956 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001957 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001958 }
1959
1960 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001961 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001962 FOR_ALL_POPULATED_CHANNELS {
1963 write_op(ctrl, channel);
1964 }
1965
1966 /* enable write leveling on all ranks
1967 * disable all DQ outputs
1968 * only NOP is allowed in this mode */
1969 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02001970 FOR_ALL_POPULATED_RANKS
1971 write_mrreg(ctrl, channel, slotrank, 1,
1972 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001973
Felix Held2bb3cdf2018-07-28 00:23:59 +02001974 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001975
1976 toggle_io_reset();
1977
1978 /* set any valid value for timB, it gets corrected later */
1979 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1980 err = discover_timB(ctrl, channel, slotrank);
1981 if (err)
1982 return err;
1983 }
1984
1985 /* disable write leveling on all ranks */
1986 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
1987 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02001988 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001989
Felix Held2bb3cdf2018-07-28 00:23:59 +02001990 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001991
1992 FOR_ALL_POPULATED_CHANNELS
1993 wait_428c(channel);
1994
1995 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02001996 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001997
1998 FOR_ALL_POPULATED_CHANNELS {
Felix Heldb802c072018-07-29 21:46:19 +02001999 volatile u32 tmp;
Felix Held2463aa92018-07-29 21:37:55 +02002000 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002001 tmp = MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002002 wait_428c(channel);
2003
2004 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002005 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2006 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2007 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2008 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002009
Felix Held9cf1dd22018-07-31 14:52:40 +02002010 // execute command queue
2011 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2012
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002013 wait_428c(channel);
2014 }
2015
2016 toggle_io_reset();
2017
2018 printram("CPE\n");
2019 precharge(ctrl);
2020 printram("CPF\n");
2021
2022 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002023 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002024 }
2025
2026 FOR_ALL_POPULATED_CHANNELS {
2027 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002028 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002029 }
2030
2031 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2032 err = discover_timC(ctrl, channel, slotrank);
2033 if (err)
2034 return err;
2035 }
2036
2037 FOR_ALL_POPULATED_CHANNELS
2038 program_timings(ctrl, channel);
2039
2040 /* measure and adjust timB timings */
2041 adjust_high_timB(ctrl);
2042
2043 FOR_ALL_POPULATED_CHANNELS
2044 program_timings(ctrl, channel);
2045
2046 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002047 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002048 }
2049 return 0;
2050}
2051
2052static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2053{
2054 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2055 int timC_delta;
2056 int lanes_ok = 0;
2057 int ctr = 0;
2058 int lane;
2059
2060 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2061 FOR_ALL_LANES {
2062 ctrl->timings[channel][slotrank].lanes[lane].timC =
2063 saved_rt.lanes[lane].timC + timC_delta;
2064 }
2065 program_timings(ctrl, channel);
2066 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002067 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002068 }
2069
Felix Held2bb3cdf2018-07-28 00:23:59 +02002070 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002071
2072 wait_428c(channel);
2073 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002074 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2075 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002076 ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002077 | 8 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002078 MCHBAR32(0x4200 + 0x400 * channel) =
2079 (slotrank << 24) | ctr | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002080 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Felix Held9fe248f2018-07-31 20:59:45 +02002081
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002082 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002083 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2084 MCHBAR32(0x4234 + 0x400 * channel) =
2085 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2086 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2087 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2088 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002089
2090 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002091 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2092 MCHBAR32(0x4238 + 0x400 * channel) =
2093 0x4001020 | (max(ctrl->tRTP, 8) << 16);
2094 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2095 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2096 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002097
2098 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002099 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2100 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2101 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2102 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002103
Felix Held9cf1dd22018-07-31 14:52:40 +02002104 // execute command queue
2105 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2106
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002107 wait_428c(channel);
2108 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002109 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002110
2111 if (r32 == 0)
2112 lanes_ok |= 1 << lane;
2113 }
2114 ctr++;
2115 if (lanes_ok == ((1 << NUM_LANES) - 1))
2116 break;
2117 }
2118
2119 ctrl->timings[channel][slotrank] = saved_rt;
2120
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002121 return lanes_ok != ((1 << NUM_LANES) - 1);
2122}
2123
2124#include "raminit_patterns.h"
2125
2126static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2127{
2128 unsigned i, j;
2129 unsigned channel_offset =
2130 get_precedening_channels(ctrl, channel) * 0x40;
2131 unsigned channel_step = 0x40 * num_of_channels(ctrl);
2132
2133 if (patno) {
2134 u8 base8 = 0x80 >> ((patno - 1) % 8);
2135 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2136 for (i = 0; i < 32; i++) {
2137 for (j = 0; j < 16; j++) {
2138 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2139 if (invert[patno - 1][i] & (1 << (j / 2)))
2140 val = ~val;
2141 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2142 j * 4), val);
2143 }
2144 }
2145
2146 } else {
2147 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2148 for (j = 0; j < 16; j++)
2149 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2150 j * 4), pattern[i][j]);
2151 }
2152 sfence();
2153 }
2154}
2155
2156static void reprogram_320c(ramctr_timing * ctrl)
2157{
2158 int channel, slotrank;
2159
2160 FOR_ALL_POPULATED_CHANNELS {
2161 wait_428c(channel);
2162
2163 /* choose an existing rank. */
2164 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2165
2166 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002167 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2168 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002169 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002170 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002171
Felix Held9cf1dd22018-07-31 14:52:40 +02002172 // execute command queue
2173 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2174
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002175 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002176 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002177 }
2178
2179 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002180 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002181 FOR_ALL_POPULATED_CHANNELS {
2182 wait_428c(channel);
2183
2184 /* choose an existing rank. */
2185 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2186
2187 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002188 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2189 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002190 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002191 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002192
Felix Held9cf1dd22018-07-31 14:52:40 +02002193 // execute command queue
2194 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2195
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002196 wait_428c(channel);
2197 }
2198
2199 /* jedec reset */
2200 dram_jedecreset(ctrl);
2201 /* mrs commands. */
2202 dram_mrscommands(ctrl);
2203
2204 toggle_io_reset();
2205}
2206
2207#define MIN_C320C_LEN 13
2208
2209static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2210{
2211 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2212 int slotrank;
2213 int c320c;
2214 int stat[NUM_SLOTRANKS][256];
2215 int delta = 0;
2216
2217 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2218
2219 FOR_ALL_POPULATED_RANKS {
2220 saved_timings[channel][slotrank] =
2221 ctrl->timings[channel][slotrank];
2222 }
2223
2224 ctrl->cmd_stretch[channel] = cmd_stretch;
2225
2226 MCHBAR32(0x4004 + 0x400 * channel) =
2227 ctrl->tRRD
2228 | (ctrl->tRTP << 4)
2229 | (ctrl->tCKE << 8)
2230 | (ctrl->tWTR << 12)
2231 | (ctrl->tFAW << 16)
2232 | (ctrl->tWR << 24)
2233 | (ctrl->cmd_stretch[channel] << 30);
2234
2235 if (ctrl->cmd_stretch[channel] == 2)
2236 delta = 2;
2237 else if (ctrl->cmd_stretch[channel] == 0)
2238 delta = 4;
2239
2240 FOR_ALL_POPULATED_RANKS {
2241 ctrl->timings[channel][slotrank].val_4024 -= delta;
2242 }
2243
2244 for (c320c = -127; c320c <= 127; c320c++) {
2245 FOR_ALL_POPULATED_RANKS {
2246 ctrl->timings[channel][slotrank].val_320c = c320c;
2247 }
2248 program_timings(ctrl, channel);
2249 reprogram_320c(ctrl);
2250 FOR_ALL_POPULATED_RANKS {
2251 stat[slotrank][c320c + 127] =
2252 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002253 }
2254 }
2255 FOR_ALL_POPULATED_RANKS {
2256 struct run rn =
2257 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002258 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002259 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2260 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002261 if (rn.all || rn.length < MIN_C320C_LEN) {
2262 FOR_ALL_POPULATED_RANKS {
2263 ctrl->timings[channel][slotrank] =
2264 saved_timings[channel][slotrank];
2265 }
2266 return MAKE_ERR;
2267 }
2268 }
2269
2270 return 0;
2271}
2272
2273/* Adjust CMD phase shift and try multiple command rates.
2274 * A command rate of 2T doubles the time needed for address and
2275 * command decode. */
2276int command_training(ramctr_timing *ctrl)
2277{
2278 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002279
2280 FOR_ALL_POPULATED_CHANNELS {
2281 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002282 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002283 }
2284
2285 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002286 int cmdrate, err;
2287
2288 /*
2289 * Dual DIMM per channel:
2290 * Issue: While c320c discovery seems to succeed raminit
2291 * will fail in write training.
2292 * Workaround: Skip 1T in dual DIMM mode, that's only
2293 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002294 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2295 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002296 *
2297 * Single DIMM per channel:
2298 * Try command rate 1T and 2T
2299 */
2300 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002301 if (ctrl->tCMD)
2302 /* XMP gives the CMD rate in clock ticks, not ns */
2303 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002304
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002305 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002306 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2307
2308 if (!err)
2309 break;
2310 }
2311
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002312 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002313 printk(BIOS_EMERG, "c320c discovery failed\n");
2314 return err;
2315 }
2316
2317 printram("Using CMD rate %uT on channel %u\n",
2318 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002319 }
2320
2321 FOR_ALL_POPULATED_CHANNELS
2322 program_timings(ctrl, channel);
2323
2324 reprogram_320c(ctrl);
2325 return 0;
2326}
2327
2328
2329static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2330 int *edges)
2331{
2332 int edge;
2333 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2334 int lane;
2335
2336 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2337 FOR_ALL_LANES {
2338 ctrl->timings[channel][slotrank].lanes[lane].rising =
2339 edge;
2340 ctrl->timings[channel][slotrank].lanes[lane].falling =
2341 edge;
2342 }
2343 program_timings(ctrl, channel);
2344
2345 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002346 volatile u32 tmp;
2347 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
2348 tmp = MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002349 }
2350
2351 wait_428c(channel);
2352 /* DRAM command MRS
2353 * write MR3 MPR enable
2354 * in this mode only RD and RDA are allowed
2355 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002356 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002357 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002358 MCHBAR32(0x4200 + 0x400 * channel) =
2359 (slotrank << 24) | 0x360004;
2360 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002361
2362 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002363 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2364 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2365 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2366 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002367
2368 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002369 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2370 MCHBAR32(0x4238 + 0x400 * channel) =
2371 0x1001 | ((ctrl->CAS + 8) << 16);
2372 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2373 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002374
2375 /* DRAM command MRS
2376 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002377 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2378 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2379 MCHBAR32(0x420c + 0x400 * channel) =
2380 (slotrank << 24) | 0x360000;
2381 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002382
Felix Held9cf1dd22018-07-31 14:52:40 +02002383 // execute command queue
2384 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002385
2386 wait_428c(channel);
2387
2388 FOR_ALL_LANES {
2389 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002390 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002391 }
2392 }
2393 FOR_ALL_LANES {
2394 struct run rn =
2395 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2396 edges[lane] = rn.middle;
2397 if (rn.all) {
2398 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2399 channel, slotrank, lane);
2400 return MAKE_ERR;
2401 }
2402 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2403 lane, edges[lane]);
2404 }
2405 return 0;
2406}
2407
2408int discover_edges(ramctr_timing *ctrl)
2409{
2410 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2411 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2412 int channel, slotrank, lane;
2413 int err;
2414
Felix Held2bb3cdf2018-07-28 00:23:59 +02002415 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002416
2417 toggle_io_reset();
2418
2419 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002420 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002421 }
2422
2423 FOR_ALL_POPULATED_CHANNELS {
2424 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002425 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002426 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002427 volatile u32 tmp;
2428 tmp = MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002429 }
2430
2431 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2432 ctrl->timings[channel][slotrank].lanes[lane].falling =
2433 16;
2434 ctrl->timings[channel][slotrank].lanes[lane].rising =
2435 16;
2436 }
2437
2438 program_timings(ctrl, channel);
2439
2440 FOR_ALL_POPULATED_RANKS {
2441 wait_428c(channel);
2442
2443 /* DRAM command MRS
2444 * MR3 enable MPR
2445 * write MR3 MPR enable
2446 * in this mode only RD and RDA are allowed
2447 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002448 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2449 MCHBAR32(0x4230 + 0x400 * channel) =
2450 0xc01 | (ctrl->tMOD << 16);
2451 MCHBAR32(0x4200 + 0x400 * channel) =
2452 (slotrank << 24) | 0x360004;
2453 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002454
2455 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002456 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2457 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2458 MCHBAR32(0x4204 + 0x400 * channel) =
2459 (slotrank << 24) | 0;
2460 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002461
2462 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002463 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2464 MCHBAR32(0x4238 + 0x400 * channel) =
2465 0x1001 | ((ctrl->CAS + 8) << 16);
2466 MCHBAR32(0x4208 + 0x400 * channel) =
2467 (slotrank << 24) | 0x60000;
2468 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002469
2470 /* DRAM command MRS
2471 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002472 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2473 MCHBAR32(0x423c + 0x400 * channel) =
2474 0xc01 | (ctrl->tMOD << 16);
2475 MCHBAR32(0x420c + 0x400 * channel) =
2476 (slotrank << 24) | 0x360000;
2477 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02002478
2479 // execute command queue
2480 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002481
2482 wait_428c(channel);
2483 }
2484
2485 /* XXX: check any measured value ? */
2486
2487 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2488 ctrl->timings[channel][slotrank].lanes[lane].falling =
2489 48;
2490 ctrl->timings[channel][slotrank].lanes[lane].rising =
2491 48;
2492 }
2493
2494 program_timings(ctrl, channel);
2495
2496 FOR_ALL_POPULATED_RANKS {
2497 wait_428c(channel);
2498
2499 /* DRAM command MRS
2500 * MR3 enable MPR
2501 * write MR3 MPR enable
2502 * in this mode only RD and RDA are allowed
2503 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002504 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2505 MCHBAR32(0x4230 + 0x400 * channel) =
2506 0xc01 | (ctrl->tMOD << 16);
2507 MCHBAR32(0x4200 + 0x400 * channel) =
2508 (slotrank << 24) | 0x360004;
2509 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002510
2511 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002512 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2513 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2514 MCHBAR32(0x4204 + 0x400 * channel) =
2515 (slotrank << 24) | 0;
2516 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002517
2518 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002519 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2520 MCHBAR32(0x4238 + 0x400 * channel) =
2521 0x1001 | ((ctrl->CAS + 8) << 16);
2522 MCHBAR32(0x4208 + 0x400 * channel) =
2523 (slotrank << 24) | 0x60000;
2524 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002525
2526 /* DRAM command MRS
2527 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002528 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2529 MCHBAR32(0x423c + 0x400 * channel) =
2530 0xc01 | (ctrl->tMOD << 16);
2531 MCHBAR32(0x420c + 0x400 * channel) =
2532 (slotrank << 24) | 0x360000;
2533 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002534
Felix Held9cf1dd22018-07-31 14:52:40 +02002535 // execute command queue
2536 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2537
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002538 wait_428c(channel);
2539 }
2540
2541 /* XXX: check any measured value ? */
2542
2543 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002544 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2545 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2546 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002547 }
2548
2549 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002550 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002551 }
2552
2553 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002554 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002555 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2556
2557 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2558 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002559 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002560 if (err)
2561 return err;
2562 }
2563
Felix Held2bb3cdf2018-07-28 00:23:59 +02002564 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002565 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2566
2567 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2568 err = discover_edges_real(ctrl, channel, slotrank,
2569 rising_edges[channel][slotrank]);
2570 if (err)
2571 return err;
2572 }
2573
Felix Held2bb3cdf2018-07-28 00:23:59 +02002574 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002575
2576 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2577 ctrl->timings[channel][slotrank].lanes[lane].falling =
2578 falling_edges[channel][slotrank][lane];
2579 ctrl->timings[channel][slotrank].lanes[lane].rising =
2580 rising_edges[channel][slotrank][lane];
2581 }
2582
2583 FOR_ALL_POPULATED_CHANNELS {
2584 program_timings(ctrl, channel);
2585 }
2586
2587 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002588 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002589 }
2590 return 0;
2591}
2592
2593static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2594 int slotrank, int *edges)
2595{
2596 int edge;
2597 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2598 int statistics[MAX_EDGE_TIMING + 1];
2599 const int reg3000b24[] = { 0, 0xc, 0x2c };
2600 int lane, i;
2601 int lower[NUM_LANES];
2602 int upper[NUM_LANES];
2603 int pat;
2604
2605 FOR_ALL_LANES {
2606 lower[lane] = 0;
2607 upper[lane] = MAX_EDGE_TIMING;
2608 }
2609
2610 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002611 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002612 printram("[%x] = 0x%08x\n",
2613 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2614 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2615 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002616 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002617 printram("using pattern %d\n", pat);
2618 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2619 FOR_ALL_LANES {
2620 ctrl->timings[channel][slotrank].lanes[lane].
2621 rising = edge;
2622 ctrl->timings[channel][slotrank].lanes[lane].
2623 falling = edge;
2624 }
2625 program_timings(ctrl, channel);
2626
2627 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002628 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002629 MCHBAR32(0x4340 + 0x400 * channel +
2630 4 * lane) = 0;
2631 tmp = MCHBAR32(0x400 * channel +
2632 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002633 }
2634 wait_428c(channel);
2635
2636 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002637 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2638 MCHBAR32(0x4230 + 0x400 * channel) =
2639 0x4 | (ctrl->tRCD << 16) |
2640 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
2641 << 10);
2642 MCHBAR32(0x4200 + 0x400 * channel) =
2643 (slotrank << 24) | 0x60000;
2644 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002645
2646 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002647 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2648 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2649 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2650 MCHBAR32(0x4204 + 0x400 * channel) =
2651 slotrank << 24;
2652 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002653
2654 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002655 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2656 MCHBAR32(0x4238 + 0x400 * channel) =
2657 0x4005020 | (max(ctrl->tRTP, 8) << 16);
2658 MCHBAR32(0x4208 + 0x400 * channel) =
2659 slotrank << 24;
2660 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002661
2662 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002663 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2664 MCHBAR32(0x423c + 0x400 * channel) =
2665 0xc01 | (ctrl->tRP << 16);
2666 MCHBAR32(0x420c + 0x400 * channel) =
2667 (slotrank << 24) | 0x60400;
2668 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002669
Felix Held9cf1dd22018-07-31 14:52:40 +02002670 // execute command queue
2671 MCHBAR32(0x4284 + 0x400 * channel) =
2672 RUN_QUEUE_4284(4);
2673
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002674 wait_428c(channel);
2675 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002676 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002677 tmp = MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002678 0x400 * channel + lane * 4);
2679 }
2680
2681 raw_statistics[edge] =
2682 MCHBAR32(0x436c + 0x400 * channel);
2683 }
2684 FOR_ALL_LANES {
2685 struct run rn;
2686 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2687 statistics[edge] =
2688 ! !(raw_statistics[edge] & (1 << lane));
2689 rn = get_longest_zero_run(statistics,
2690 MAX_EDGE_TIMING + 1);
2691 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2692 channel, slotrank, i, rn.start, rn.middle,
2693 rn.end, rn.start + ctrl->edge_offset[i],
2694 rn.end - ctrl->edge_offset[i]);
2695 lower[lane] =
2696 max(rn.start + ctrl->edge_offset[i], lower[lane]);
2697 upper[lane] =
2698 min(rn.end - ctrl->edge_offset[i], upper[lane]);
2699 edges[lane] = (lower[lane] + upper[lane]) / 2;
2700 if (rn.all || (lower[lane] > upper[lane])) {
2701 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2702 channel, slotrank, lane);
2703 return MAKE_ERR;
2704 }
2705 }
2706 }
2707 }
2708
Felix Held2bb3cdf2018-07-28 00:23:59 +02002709 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002710 printram("CPA\n");
2711 return 0;
2712}
2713
2714int discover_edges_write(ramctr_timing *ctrl)
2715{
2716 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2717 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2718 int channel, slotrank, lane;
2719 int err;
2720
2721 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002722 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002723 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2724
2725 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2726 err = discover_edges_write_real(ctrl, channel, slotrank,
2727 falling_edges[channel][slotrank]);
2728 if (err)
2729 return err;
2730 }
2731
Felix Held2bb3cdf2018-07-28 00:23:59 +02002732 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002733 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2734
2735 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2736 err = discover_edges_write_real(ctrl, channel, slotrank,
2737 rising_edges[channel][slotrank]);
2738 if (err)
2739 return err;
2740 }
2741
Felix Held2bb3cdf2018-07-28 00:23:59 +02002742 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002743
2744 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2745 ctrl->timings[channel][slotrank].lanes[lane].falling =
2746 falling_edges[channel][slotrank][lane];
2747 ctrl->timings[channel][slotrank].lanes[lane].rising =
2748 rising_edges[channel][slotrank][lane];
2749 }
2750
2751 FOR_ALL_POPULATED_CHANNELS
2752 program_timings(ctrl, channel);
2753
2754 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002755 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002756 }
2757 return 0;
2758}
2759
2760static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2761{
2762 wait_428c(channel);
2763 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002764 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2765 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002766 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002767 << 10) | (ctrl->tRCD << 16) | 4;
2768 MCHBAR32(0x4200 + 0x400 * channel) =
2769 (slotrank << 24) | 0x60000;
2770 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002771
2772 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002773 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2774 MCHBAR32(0x4234 + 0x400 * channel) =
2775 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2776 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2777 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002778
2779 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002780 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2781 MCHBAR32(0x4238 + 0x400 * channel) =
2782 0x40011e0 | (max(ctrl->tRTP, 8) << 16);
2783 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2784 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002785
2786 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002787 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2788 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2789 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2790 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002791
Felix Held9cf1dd22018-07-31 14:52:40 +02002792 // execute command queue
2793 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2794
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002795 wait_428c(channel);
2796}
2797
2798int discover_timC_write(ramctr_timing *ctrl)
2799{
2800 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2801 int i, pat;
2802
2803 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2804 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2805 int channel, slotrank, lane;
2806
2807 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2808 lower[channel][slotrank][lane] = 0;
2809 upper[channel][slotrank][lane] = MAX_TIMC;
2810 }
2811
Felix Held2bb3cdf2018-07-28 00:23:59 +02002812 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002813 printram("discover timC write:\n");
2814
2815 for (i = 0; i < 3; i++)
2816 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002817 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2818 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002819 udelay(2);
2820 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2821 FOR_ALL_POPULATED_RANKS {
2822 int timC;
2823 u32 raw_statistics[MAX_TIMC + 1];
2824 int statistics[MAX_TIMC + 1];
2825
2826 /* Make sure rn.start < rn.end */
2827 statistics[MAX_TIMC] = 1;
2828
2829 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002830 MCHBAR32(0x4288 + 0x400 * channel) =
2831 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002832 for (timC = 0; timC < MAX_TIMC; timC++) {
2833 FOR_ALL_LANES
2834 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2835 program_timings(ctrl, channel);
2836
2837 test_timC_write (ctrl, channel, slotrank);
2838
2839 raw_statistics[timC] =
2840 MCHBAR32(0x436c + 0x400 * channel);
2841 }
2842 FOR_ALL_LANES {
2843 struct run rn;
2844 for (timC = 0; timC < MAX_TIMC; timC++)
2845 statistics[timC] =
2846 !!(raw_statistics[timC] &
2847 (1 << lane));
2848
2849 rn = get_longest_zero_run(statistics,
2850 MAX_TIMC + 1);
2851 if (rn.all) {
2852 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2853 channel, slotrank, lane);
2854 return MAKE_ERR;
2855 }
2856 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2857 channel, slotrank, i, rn.start,
2858 rn.middle, rn.end,
2859 rn.start + ctrl->timC_offset[i],
2860 rn.end - ctrl->timC_offset[i]);
2861 lower[channel][slotrank][lane] =
2862 max(rn.start + ctrl->timC_offset[i],
2863 lower[channel][slotrank][lane]);
2864 upper[channel][slotrank][lane] =
2865 min(rn.end - ctrl->timC_offset[i],
2866 upper[channel][slotrank][lane]);
2867
2868 }
2869 }
2870 }
2871 }
2872
2873 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002874 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002875 udelay(2);
2876 }
2877
Felix Held2bb3cdf2018-07-28 00:23:59 +02002878 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002879
2880 printram("CPB\n");
2881
2882 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2883 printram("timC %d, %d, %d: %x\n", channel,
2884 slotrank, lane,
2885 (lower[channel][slotrank][lane] +
2886 upper[channel][slotrank][lane]) / 2);
2887 ctrl->timings[channel][slotrank].lanes[lane].timC =
2888 (lower[channel][slotrank][lane] +
2889 upper[channel][slotrank][lane]) / 2;
2890 }
2891 FOR_ALL_POPULATED_CHANNELS {
2892 program_timings(ctrl, channel);
2893 }
2894 return 0;
2895}
2896
2897void normalize_training(ramctr_timing * ctrl)
2898{
2899 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002900 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002901
2902 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2903 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002904 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002905 FOR_ALL_LANES mat =
2906 max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002907 printram("normalize %d, %d, %d: mat %d\n",
2908 channel, slotrank, lane, mat);
2909
2910 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2911 printram("normalize %d, %d, %d: delta %d\n",
2912 channel, slotrank, lane, delta);
2913
2914 ctrl->timings[channel][slotrank].val_4024 += delta;
2915 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002916 }
2917
2918 FOR_ALL_POPULATED_CHANNELS {
2919 program_timings(ctrl, channel);
2920 }
2921}
2922
2923void write_controller_mr(ramctr_timing * ctrl)
2924{
2925 int channel, slotrank;
2926
2927 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002928 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2929 make_mr0(ctrl, slotrank);
2930 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2931 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002932 }
2933}
2934
2935int channel_test(ramctr_timing *ctrl)
2936{
2937 int channel, slotrank, lane;
2938
2939 slotrank = 0;
2940 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002941 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002942 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2943 channel);
2944 return MAKE_ERR;
2945 }
2946 FOR_ALL_POPULATED_CHANNELS {
2947 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2948
Felix Held2bb3cdf2018-07-28 00:23:59 +02002949 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002950 }
2951
2952 for (slotrank = 0; slotrank < 4; slotrank++)
2953 FOR_ALL_CHANNELS
2954 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2955 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002956 MCHBAR32(0x4f40 + 4 * lane) = 0;
2957 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002958 }
2959 wait_428c(channel);
Felix Held9cf1dd22018-07-31 14:52:40 +02002960
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002961 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002962 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2963 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2964 MCHBAR32(0x4200 + (channel << 10)) =
2965 0x00060000 | (slotrank << 24);
2966 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Felix Held9cf1dd22018-07-31 14:52:40 +02002967
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002968 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002969 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2970 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2971 MCHBAR32(0x4204 + (channel << 10)) =
2972 0x00000000 | (slotrank << 24);
2973 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002974
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002975 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002976 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
2977 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
2978 MCHBAR32(0x4208 + (channel << 10)) =
2979 0x00000000 | (slotrank << 24);
2980 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002981
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002982 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002983 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
2984 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
2985 MCHBAR32(0x420c + (channel << 10)) =
2986 0x00060400 | (slotrank << 24);
2987 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
Felix Held9cf1dd22018-07-31 14:52:40 +02002988
2989 // execute command queue
2990 MCHBAR32(0x4284 + (channel << 10)) = RUN_QUEUE_4284(4);
2991
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002992 wait_428c(channel);
2993 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02002994 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002995 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
2996 channel, slotrank, lane);
2997 return MAKE_ERR;
2998 }
2999 }
3000 return 0;
3001}
3002
3003void set_scrambling_seed(ramctr_timing * ctrl)
3004{
3005 int channel;
3006
3007 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
3008 I don't think so. */
3009 static u32 seeds[NUM_CHANNELS][3] = {
3010 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
3011 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
3012 };
3013 FOR_ALL_POPULATED_CHANNELS {
3014 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02003015 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
3016 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
3017 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003018 }
3019}
3020
3021void set_4f8c(void)
3022{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003023 u32 cpu;
3024
Subrata Banik53b08c32018-12-10 14:11:35 +05303025 cpu = cpu_get_cpuid();
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003026 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3027 MCHBAR32(0x4f8c) = 0x141D1519;
3028 } else {
3029 MCHBAR32(0x4f8c) = 0x551D1519;
3030 }
3031}
3032
3033void prepare_training(ramctr_timing * ctrl)
3034{
3035 int channel;
3036
3037 FOR_ALL_POPULATED_CHANNELS {
3038 // Always drive command bus
Felix Held9fe248f2018-07-31 20:59:45 +02003039 MCHBAR32_OR(0x4004 + 0x400 * channel, 0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003040 }
3041
3042 udelay(1);
3043
3044 FOR_ALL_POPULATED_CHANNELS {
3045 wait_428c(channel);
3046 }
3047}
3048
3049void set_4008c(ramctr_timing * ctrl)
3050{
3051 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003052
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003053 FOR_ALL_POPULATED_CHANNELS {
3054 u32 b20, b4_8_12;
3055 int min_320c = 10000;
3056 int max_320c = -10000;
3057
3058 FOR_ALL_POPULATED_RANKS {
3059 max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c);
3060 min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c);
3061 }
3062
3063 if (max_320c - min_320c > 51)
3064 b20 = 0;
3065 else
3066 b20 = ctrl->ref_card_offset[channel];
3067
3068 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3069 b4_8_12 = 0x3330;
3070 else
3071 b4_8_12 = 0x2220;
3072
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003073 dram_odt_stretch(ctrl, channel);
3074
Felix Held2bb3cdf2018-07-28 00:23:59 +02003075 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003076 0x0a000000 | (b20 << 20) |
3077 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003078 }
3079}
3080
3081void set_42a0(ramctr_timing * ctrl)
3082{
3083 int channel;
3084 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003085 MCHBAR32(0x42a0 + 0x400 * channel) =
3086 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003087 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003088 }
3089}
3090
3091static int encode_5d10(int ns)
3092{
3093 return (ns + 499) / 500;
3094}
3095
3096/* FIXME: values in this function should be hardware revision-dependent. */
3097void final_registers(ramctr_timing * ctrl)
3098{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003099 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3100
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003101 int channel;
3102 int t1_cycles = 0, t1_ns = 0, t2_ns;
3103 int t3_ns;
3104 u32 r32;
3105
Felix Held2bb3cdf2018-07-28 00:23:59 +02003106 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003107
Felix Heldf9b826a2018-07-30 17:56:52 +02003108 FOR_ALL_CHANNELS
3109 MCHBAR32_AND_OR(0x400c + 0x400 * channel, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003110
Patrick Rudolph74203de2017-11-20 11:57:01 +01003111 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003112 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3113 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3114 else
3115 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3116 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3117
Felix Heldf9b826a2018-07-30 17:56:52 +02003118 FOR_ALL_CHANNELS
3119 MCHBAR32(0x4380 + 0x400 * channel) = 0x00000aaa;
3120
Felix Held2bb3cdf2018-07-28 00:23:59 +02003121 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3122 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003123
3124 FOR_ALL_CHANNELS {
3125 switch (ctrl->rankmap[channel]) {
3126 /* Unpopulated channel. */
3127 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003128 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003129 break;
3130 /* Only single-ranked dimms. */
3131 case 1:
3132 case 4:
3133 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003134 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003135 break;
3136 /* Dual-ranked dimms present. */
3137 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003138 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003139 break;
3140 }
3141 }
3142
Felix Held2bb3cdf2018-07-28 00:23:59 +02003143 MCHBAR32(0x5880) = 0xca9171e5;
Felix Held2463aa92018-07-29 21:37:55 +02003144 MCHBAR32_AND_OR(0x5888, ~0xffffff, 0xe4d5d0);
3145 MCHBAR32_AND(0x58a8, ~0x1f);
Felix Heldf9b826a2018-07-30 17:56:52 +02003146
3147 FOR_ALL_CHANNELS
3148 MCHBAR32_AND_OR(0x4294 + 0x400 * channel, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003149
Felix Held9fe248f2018-07-31 20:59:45 +02003150 MCHBAR32_OR(0x5030, 1);
3151 MCHBAR32_OR(0x5030, 0x80);
Felix Held2463aa92018-07-29 21:37:55 +02003152 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003153
3154 /* Find a populated channel. */
3155 FOR_ALL_POPULATED_CHANNELS
3156 break;
3157
Felix Held2bb3cdf2018-07-28 00:23:59 +02003158 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3159 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003160 if (r32 & 0x20000)
3161 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003162 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003163 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3164 if (!(r32 & 0x20000))
3165 t1_ns += 500;
3166
Felix Held2bb3cdf2018-07-28 00:23:59 +02003167 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3168 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003169 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003170 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3171 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003172 }
3173 else
3174 {
3175 t3_ns = 500;
3176 }
3177 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3178 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003179 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3180 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003181 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003182 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003183}
3184
3185void restore_timings(ramctr_timing * ctrl)
3186{
3187 int channel, slotrank, lane;
3188
3189 FOR_ALL_POPULATED_CHANNELS
3190 MCHBAR32(0x4004 + 0x400 * channel) =
3191 ctrl->tRRD
3192 | (ctrl->tRTP << 4)
3193 | (ctrl->tCKE << 8)
3194 | (ctrl->tWTR << 12)
3195 | (ctrl->tFAW << 16)
3196 | (ctrl->tWR << 24)
3197 | (ctrl->cmd_stretch[channel] << 30);
3198
3199 udelay(1);
3200
3201 FOR_ALL_POPULATED_CHANNELS {
3202 wait_428c(channel);
3203 }
3204
3205 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003206 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003207 }
3208
3209 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003210 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003211
3212 FOR_ALL_POPULATED_CHANNELS {
3213 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003214 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003215 }
3216
3217 printram("CPE\n");
3218
Felix Held2bb3cdf2018-07-28 00:23:59 +02003219 MCHBAR32(0x3400) = 0;
3220 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003221
3222 printram("CP5b\n");
3223
3224 FOR_ALL_POPULATED_CHANNELS {
3225 program_timings(ctrl, channel);
3226 }
3227
3228 u32 reg, addr;
3229
3230 while (!(MCHBAR32(0x5084) & 0x10000));
3231 do {
3232 reg = MCHBAR32(0x428c);
3233 } while ((reg & 0x14) == 0);
3234
3235 // Set state of memory controller
3236 MCHBAR32(0x5030) = 0x116;
3237 MCHBAR32(0x4ea0) = 0;
3238
3239 // Wait 500us
3240 udelay(500);
3241
3242 FOR_ALL_CHANNELS {
3243 // Set valid rank CKE
3244 reg = 0;
3245 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3246 addr = 0x400 * channel + 0x42a0;
3247 MCHBAR32(addr) = reg;
3248
3249 // Wait 10ns for ranks to settle
3250 //udelay(0.01);
3251
3252 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3253 MCHBAR32(addr) = reg;
3254
3255 // Write reset using a NOP
3256 write_reset(ctrl);
3257 }
3258
3259 /* mrs commands. */
3260 dram_mrscommands(ctrl);
3261
3262 printram("CP5c\n");
3263
Felix Held2bb3cdf2018-07-28 00:23:59 +02003264 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003265
3266 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003267 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003268 udelay(2);
3269 }
3270
Felix Held2bb3cdf2018-07-28 00:23:59 +02003271 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003272}