blob: 44e5d3a8ff50616bbc199faa2f644bc328c16285 [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
Elyes HAOUASf97c1c92019-12-03 18:22:06 +010018#include <commonlib/helpers.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010019#include <console/console.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010020#include <string.h>
Subrata Banik53b08c32018-12-10 14:11:35 +053021#include <arch/cpu.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020022#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020023#include <device/pci_ops.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010024#include <northbridge/intel/sandybridge/chip.h>
25#include <device/pci_def.h>
26#include <delay.h>
Elyes HAOUAS1d3b3c32019-05-04 08:12:42 +020027
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010028#include "raminit_native.h"
29#include "raminit_common.h"
30#include "sandybridge.h"
31
32/* FIXME: no ECC support. */
33/* FIXME: no support for 3-channel chipsets. */
34
35/*
36 * Register description:
37 * Intel provides a command queue of depth four.
38 * Every command is configured by using multiple registers.
39 * On executing the command queue you have to provide the depth used.
40 *
41 * Known registers:
42 * Channel X = [0, 1]
43 * Command queue index Y = [0, 1, 2, 3]
44 *
45 * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register
46 * Controls the DRAM command signals
47 * Bit 0: !RAS
48 * Bit 1: !CAS
49 * Bit 2: !WE
50 *
51 * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register
52 * Controls the address, bank address and slotrank signals
53 * Bit 0-15 : Address
54 * Bit 20-22: Bank Address
55 * Bit 24-25: slotrank
56 *
57 * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register
58 * Controls the idle time after issuing this DRAM command
59 * Bit 16-32: number of clock-cylces to idle
60 *
61 * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue
62 * Starts to execute all queued commands
63 * Bit 0 : start DRAM command execution
Felix Held9cf1dd22018-07-31 14:52:40 +020064 * Bit 18-19 : number of queued commands - 1
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010065 */
66
Felix Held9cf1dd22018-07-31 14:52:40 +020067#define RUN_QUEUE_4284(x) ((((x) - 1) << 18) | 1) // 0 <= x < 4
68
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010069static void sfence(void)
70{
71 asm volatile ("sfence");
72}
73
74static void toggle_io_reset(void) {
75 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020076 u32 r32 = MCHBAR32(0x5030);
77 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010078 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020079 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010080 udelay(1);
81}
82
83static u32 get_XOVER_CLK(u8 rankmap)
84{
85 return rankmap << 24;
86}
87
88static u32 get_XOVER_CMD(u8 rankmap)
89{
90 u32 reg;
91
92 // enable xover cmd
93 reg = 0x4000;
94
95 // enable xover ctl
96 if (rankmap & 0x3)
97 reg |= 0x20000;
98
99 if (rankmap & 0xc)
100 reg |= 0x4000000;
101
102 return reg;
103}
104
105/* CAS write latency. To be programmed in MR2.
106 * See DDR3 SPEC for MR2 documentation. */
107u8 get_CWL(u32 tCK)
108{
109 /* Get CWL based on tCK using the following rule: */
110 switch (tCK) {
111 case TCK_1333MHZ:
112 return 12;
113 case TCK_1200MHZ:
114 case TCK_1100MHZ:
115 return 11;
116 case TCK_1066MHZ:
117 case TCK_1000MHZ:
118 return 10;
119 case TCK_933MHZ:
120 case TCK_900MHZ:
121 return 9;
122 case TCK_800MHZ:
123 case TCK_700MHZ:
124 return 8;
125 case TCK_666MHZ:
126 return 7;
127 case TCK_533MHZ:
128 return 6;
129 default:
130 return 5;
131 }
132}
133
134void dram_find_common_params(ramctr_timing *ctrl)
135{
136 size_t valid_dimms;
137 int channel, slot;
138 dimm_info *dimms = &ctrl->info;
139
140 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
141 valid_dimms = 0;
142 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
143 const dimm_attr *dimm = &dimms->dimm[channel][slot];
144 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
145 continue;
146 valid_dimms++;
147
148 /* Find all possible CAS combinations */
149 ctrl->cas_supported &= dimm->cas_supported;
150
151 /* Find the smallest common latencies supported by all DIMMs */
152 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
153 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
154 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
155 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
156 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
157 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
158 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
159 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
160 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
161 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
162 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300163 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
164 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100165 }
166
167 if (!ctrl->cas_supported)
168 die("Unsupported DIMM combination. "
169 "DIMMS do not support common CAS latency");
170 if (!valid_dimms)
171 die("No valid DIMMs found");
172}
173
174void dram_xover(ramctr_timing * ctrl)
175{
176 u32 reg;
177 int channel;
178
179 FOR_ALL_CHANNELS {
180 // enable xover clk
181 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
182 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
183 reg);
184 MCHBAR32(channel * 0x100 + 0xc14) = reg;
185
186 // enable xover ctl & xover cmd
187 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
188 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
189 reg);
190 MCHBAR32(0x100 * channel + 0x320c) = reg;
191 }
192}
193
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100194static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100195{
Iru Cai89af71c2018-08-16 16:46:27 +0800196 u32 addr, cpu, stretch;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100197
198 stretch = ctrl->ref_card_offset[channel];
199 /* ODT stretch: Delay ODT signal by stretch value.
200 * Useful for multi DIMM setups on the same channel. */
Subrata Banik53b08c32018-12-10 14:11:35 +0530201 cpu = cpu_get_cpuid();
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100202 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
203 if (stretch == 2)
204 stretch = 3;
Iru Cai89af71c2018-08-16 16:46:27 +0800205 addr = 0x401c + 0x400 * channel;
206 MCHBAR32_AND_OR(addr, 0xffffc3ff,
Felix Held9fe248f2018-07-31 20:59:45 +0200207 (stretch << 12) | (stretch << 10));
Iru Cai89af71c2018-08-16 16:46:27 +0800208 printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr,
209 MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100210 } else {
211 // OTHP
Iru Cai89af71c2018-08-16 16:46:27 +0800212 addr = 0x400c + 0x400 * channel;
213 MCHBAR32_AND_OR(addr, 0xfff0ffff,
Felix Held9fe248f2018-07-31 20:59:45 +0200214 (stretch << 16) | (stretch << 18));
Iru Cai89af71c2018-08-16 16:46:27 +0800215 printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100216 }
217}
218
219void dram_timing_regs(ramctr_timing *ctrl)
220{
221 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100222 int channel;
223
224 FOR_ALL_CHANNELS {
225 // DBP
226 reg = 0;
227 reg |= ctrl->tRCD;
228 reg |= (ctrl->tRP << 4);
229 reg |= (ctrl->CAS << 8);
230 reg |= (ctrl->CWL << 12);
231 reg |= (ctrl->tRAS << 16);
232 printram("DBP [%x] = %x\n", 0x400 * channel + 0x4000, reg);
233 MCHBAR32(0x400 * channel + 0x4000) = reg;
234
235 // RAP
236 reg = 0;
237 reg |= ctrl->tRRD;
238 reg |= (ctrl->tRTP << 4);
239 reg |= (ctrl->tCKE << 8);
240 reg |= (ctrl->tWTR << 12);
241 reg |= (ctrl->tFAW << 16);
242 reg |= (ctrl->tWR << 24);
243 reg |= (3 << 30);
244 printram("RAP [%x] = %x\n", 0x400 * channel + 0x4004, reg);
245 MCHBAR32(0x400 * channel + 0x4004) = reg;
246
247 // OTHP
248 addr = 0x400 * channel + 0x400c;
249 reg = 0;
250 reg |= ctrl->tXPDLL;
251 reg |= (ctrl->tXP << 5);
252 reg |= (ctrl->tAONPD << 8);
253 reg |= 0xa0000;
254 printram("OTHP [%x] = %x\n", addr, reg);
255 MCHBAR32(addr) = reg;
256
257 MCHBAR32(0x400 * channel + 0x4014) = 0;
258
Felix Held9fe248f2018-07-31 20:59:45 +0200259 MCHBAR32_OR(addr, 0x00020000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100260
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100261 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100262
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100263 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200264 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100265 * The tREFIx9 field should be programmed to minimum of
266 * 8.9*tREFI (to allow for possible delays from ZQ or
267 * isoc) and tRASmax (70us) divided by 1024.
268 */
269 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
270
271 reg = ((ctrl->tREFI & 0xffff) << 0) |
272 ((ctrl->tRFC & 0x1ff) << 16) |
273 (((val32 / 1024) & 0x7f) << 25);
274 printram("REFI [%x] = %x\n", 0x400 * channel + 0x4298, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100275 MCHBAR32(0x400 * channel + 0x4298) = reg;
276
Felix Held9fe248f2018-07-31 20:59:45 +0200277 MCHBAR32_OR(0x400 * channel + 0x4294, 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100278
279 // SRFTP
280 reg = 0;
281 val32 = tDLLK;
282 reg = (reg & ~0xfff) | val32;
283 val32 = ctrl->tXSOffset;
284 reg = (reg & ~0xf000) | (val32 << 12);
285 val32 = tDLLK - ctrl->tXSOffset;
286 reg = (reg & ~0x3ff0000) | (val32 << 16);
287 val32 = ctrl->tMOD - 8;
288 reg = (reg & ~0xf0000000) | (val32 << 28);
289 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
290 reg);
291 MCHBAR32(0x400 * channel + 0x42a4) = reg;
292 }
293}
294
295void dram_dimm_mapping(ramctr_timing *ctrl)
296{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100297 int channel;
298 dimm_info *info = &ctrl->info;
299
300 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200301 dimm_attr *dimmA, *dimmB;
302 u32 reg = 0;
303
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100304 if (info->dimm[channel][0].size_mb >=
305 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100306 dimmA = &info->dimm[channel][0];
307 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200308 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100309 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100310 dimmA = &info->dimm[channel][1];
311 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200312 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100313 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100314
Nico Huberac4f2162017-10-01 18:14:43 +0200315 if (dimmA && (dimmA->ranks > 0)) {
316 reg |= dimmA->size_mb / 256;
317 reg |= (dimmA->ranks - 1) << 17;
318 reg |= (dimmA->width / 8 - 1) << 19;
319 }
320
321 if (dimmB && (dimmB->ranks > 0)) {
322 reg |= (dimmB->size_mb / 256) << 8;
323 reg |= (dimmB->ranks - 1) << 18;
324 reg |= (dimmB->width / 8 - 1) << 20;
325 }
326
327 reg |= 1 << 21; /* rank interleave */
328 reg |= 1 << 22; /* enhanced interleave */
329
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100330 if ((dimmA && (dimmA->ranks > 0))
331 || (dimmB && (dimmB->ranks > 0))) {
332 ctrl->mad_dimm[channel] = reg;
333 } else {
334 ctrl->mad_dimm[channel] = 0;
335 }
336 }
337}
338
339void dram_dimm_set_mapping(ramctr_timing * ctrl)
340{
341 int channel;
342 FOR_ALL_CHANNELS {
343 MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
344 }
345}
346
347void dram_zones(ramctr_timing * ctrl, int training)
348{
349 u32 reg, ch0size, ch1size;
350 u8 val;
351 reg = 0;
352 val = 0;
353 if (training) {
354 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
355 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
356 } else {
357 ch0size = ctrl->channel_size_mb[0];
358 ch1size = ctrl->channel_size_mb[1];
359 }
360
361 if (ch0size >= ch1size) {
362 reg = MCHBAR32(0x5014);
363 val = ch1size / 256;
364 reg = (reg & ~0xff000000) | val << 24;
365 reg = (reg & ~0xff0000) | (2 * val) << 16;
366 MCHBAR32(0x5014) = reg;
367 MCHBAR32(0x5000) = 0x24;
368 } else {
369 reg = MCHBAR32(0x5014);
370 val = ch0size / 256;
371 reg = (reg & ~0xff000000) | val << 24;
372 reg = (reg & ~0xff0000) | (2 * val) << 16;
373 MCHBAR32(0x5014) = reg;
374 MCHBAR32(0x5000) = 0x21;
375 }
376}
377
378#define HOST_BRIDGE PCI_DEVFN(0, 0)
379#define DEFAULT_TCK TCK_800MHZ
380
381unsigned int get_mem_min_tck(void)
382{
383 u32 reg32;
384 u8 rev;
385 const struct device *dev;
386 const struct northbridge_intel_sandybridge_config *cfg = NULL;
387
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300388 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100389 if (dev)
390 cfg = dev->chip_info;
391
392 /* If this is zero, it just means devicetree.cb didn't set it */
393 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Julius Wernercd49cce2019-03-05 16:53:33 -0800394 if (CONFIG(NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
Patrick Rudolphb794a692017-08-08 13:13:51 +0200395 return TCK_1333MHZ;
396
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100397 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
398
399 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
400 /* read Capabilities A Register DMFC bits */
401 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
402 reg32 &= 0x7;
403
404 switch (reg32) {
405 case 7: return TCK_533MHZ;
406 case 6: return TCK_666MHZ;
407 case 5: return TCK_800MHZ;
408 /* reserved: */
409 default:
410 break;
411 }
412 } else {
413 /* read Capabilities B Register DMFC bits */
414 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
415 reg32 = (reg32 >> 4) & 0x7;
416
417 switch (reg32) {
418 case 7: return TCK_533MHZ;
419 case 6: return TCK_666MHZ;
420 case 5: return TCK_800MHZ;
421 case 4: return TCK_933MHZ;
422 case 3: return TCK_1066MHZ;
423 case 2: return TCK_1200MHZ;
424 case 1: return TCK_1333MHZ;
425 /* reserved: */
426 default:
427 break;
428 }
429 }
430 return DEFAULT_TCK;
431 } else {
432 if (cfg->max_mem_clock_mhz >= 1066)
433 return TCK_1066MHZ;
434 else if (cfg->max_mem_clock_mhz >= 933)
435 return TCK_933MHZ;
436 else if (cfg->max_mem_clock_mhz >= 800)
437 return TCK_800MHZ;
438 else if (cfg->max_mem_clock_mhz >= 666)
439 return TCK_666MHZ;
440 else if (cfg->max_mem_clock_mhz >= 533)
441 return TCK_533MHZ;
442 else
443 return TCK_400MHZ;
444 }
445}
446
447#define DEFAULT_PCI_MMIO_SIZE 2048
448
449static unsigned int get_mmio_size(void)
450{
451 const struct device *dev;
452 const struct northbridge_intel_sandybridge_config *cfg = NULL;
453
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300454 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100455 if (dev)
456 cfg = dev->chip_info;
457
458 /* If this is zero, it just means devicetree.cb didn't set it */
459 if (!cfg || cfg->pci_mmio_size == 0)
460 return DEFAULT_PCI_MMIO_SIZE;
461 else
462 return cfg->pci_mmio_size;
463}
464
465void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
466{
467 u32 reg, val, reclaim;
468 u32 tom, gfxstolen, gttsize;
469 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
470 tsegbase, mestolenbase;
471 size_t tsegbasedelta, remapbase, remaplimit;
472 uint16_t ggc;
473
474 mmiosize = get_mmio_size();
475
476 ggc = pci_read_config16(NORTHBRIDGE, GGC);
477 if (!(ggc & 2)) {
478 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
479 gttsize = ((ggc >> 8) & 0x3);
480 } else {
481 gfxstolen = 0;
482 gttsize = 0;
483 }
484
485 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
486
487 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
488
489 mestolenbase = tom - me_uma_size;
490
491 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
492 tom - me_uma_size);
493 gfxstolenbase = toludbase - gfxstolen;
494 gttbase = gfxstolenbase - gttsize;
495
496 tsegbase = gttbase - tsegsize;
497
498 // Round tsegbase down to nearest address aligned to tsegsize
499 tsegbasedelta = tsegbase & (tsegsize - 1);
500 tsegbase &= ~(tsegsize - 1);
501
502 gttbase -= tsegbasedelta;
503 gfxstolenbase -= tsegbasedelta;
504 toludbase -= tsegbasedelta;
505
506 // Test if it is possible to reclaim a hole in the RAM addressing
507 if (tom - me_uma_size > toludbase) {
508 // Reclaim is possible
509 reclaim = 1;
510 remapbase = MAX(4096, tom - me_uma_size);
511 remaplimit =
512 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
513 touudbase = remaplimit + 1;
514 } else {
515 // Reclaim not possible
516 reclaim = 0;
517 touudbase = tom - me_uma_size;
518 }
519
520 // Update memory map in pci-e configuration space
521 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
522
523 // TOM (top of memory)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300524 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100525 val = tom & 0xfff;
526 reg = (reg & ~0xfff00000) | (val << 20);
527 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300528 pci_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100529
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300530 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100531 val = tom & 0xfffff000;
532 reg = (reg & ~0x000fffff) | (val >> 12);
533 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300534 pci_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100535
536 // TOLUD (top of low used dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300537 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xbc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100538 val = toludbase & 0xfff;
539 reg = (reg & ~0xfff00000) | (val << 20);
540 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xbc, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300541 pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100542
543 // TOUUD LSB (top of upper usable dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300544 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100545 val = touudbase & 0xfff;
546 reg = (reg & ~0xfff00000) | (val << 20);
547 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300548 pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100549
550 // TOUUD MSB
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300551 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xac);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100552 val = touudbase & 0xfffff000;
553 reg = (reg & ~0x000fffff) | (val >> 12);
554 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xac, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300555 pci_write_config32(PCI_DEV(0, 0, 0), 0xac, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100556
557 if (reclaim) {
558 // REMAP BASE
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300559 pci_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20);
560 pci_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100561
562 // REMAP LIMIT
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300563 pci_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20);
564 pci_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100565 }
566 // TSEG
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300567 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100568 val = tsegbase & 0xfff;
569 reg = (reg & ~0xfff00000) | (val << 20);
570 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300571 pci_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100572
573 // GFX stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300574 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100575 val = gfxstolenbase & 0xfff;
576 reg = (reg & ~0xfff00000) | (val << 20);
577 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300578 pci_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100579
580 // GTT stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300581 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100582 val = gttbase & 0xfff;
583 reg = (reg & ~0xfff00000) | (val << 20);
584 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300585 pci_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100586
587 if (me_uma_size) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300588 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x7c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100589 val = (0x80000 - me_uma_size) & 0xfffff000;
590 reg = (reg & ~0x000fffff) | (val >> 12);
591 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x7c, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300592 pci_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100593
594 // ME base
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300595 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x70);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100596 val = mestolenbase & 0xfff;
597 reg = (reg & ~0xfff00000) | (val << 20);
598 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x70, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300599 pci_write_config32(PCI_DEV(0, 0, 0), 0x70, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100600
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300601 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x74);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100602 val = mestolenbase & 0xfffff000;
603 reg = (reg & ~0x000fffff) | (val >> 12);
604 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x74, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300605 pci_write_config32(PCI_DEV(0, 0, 0), 0x74, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100606
607 // ME mask
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300608 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x78);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100609 val = (0x80000 - me_uma_size) & 0xfff;
610 reg = (reg & ~0xfff00000) | (val << 20);
611 reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem
612
613 reg = (reg & ~0x800) | (1 << 11); // set ME memory enable
614 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x78, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300615 pci_write_config32(PCI_DEV(0, 0, 0), 0x78, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100616 }
617}
618
619static void wait_428c(int channel)
620{
621 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200622 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100623 return;
624 }
625}
626
627static void write_reset(ramctr_timing * ctrl)
628{
629 int channel, slotrank;
630
631 /* choose a populated channel. */
632 channel = (ctrl->rankmap[0]) ? 0 : 1;
633
634 wait_428c(channel);
635
636 /* choose a populated rank. */
637 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
638
639 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200640 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
641 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200642 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200643 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100644
Felix Held9cf1dd22018-07-31 14:52:40 +0200645 // execute command queue - why is bit 22 set here?!
646 MCHBAR32(0x4284 + 0x400 * channel) = (1 << 22) | RUN_QUEUE_4284(1);
647
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100648 wait_428c(channel);
649}
650
651void dram_jedecreset(ramctr_timing * ctrl)
652{
Felix Held9fe248f2018-07-31 20:59:45 +0200653 u32 reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100654 int channel;
655
656 while (!(MCHBAR32(0x5084) & 0x10000));
657 do {
658 reg = MCHBAR32(0x428c);
659 } while ((reg & 0x14) == 0);
660
661 // Set state of memory controller
662 reg = 0x112;
663 MCHBAR32(0x5030) = reg;
664 MCHBAR32(0x4ea0) = 0;
665 reg |= 2; //ddr reset
666 MCHBAR32(0x5030) = reg;
667
668 // Assert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200669 MCHBAR32_AND(0x5030, ~0x2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100670
671 // Wait 200us
672 udelay(200);
673
674 // Deassert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200675 MCHBAR32_OR(0x5030, 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100676
677 // Wait 500us
678 udelay(500);
679
680 // Enable DCLK
Felix Held9fe248f2018-07-31 20:59:45 +0200681 MCHBAR32_OR(0x5030, 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100682
683 // XXX Wait 20ns
684 udelay(1);
685
686 FOR_ALL_CHANNELS {
687 // Set valid rank CKE
Felix Held9fe248f2018-07-31 20:59:45 +0200688 reg = ctrl->rankmap[channel];
689 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100690
691 // Wait 10ns for ranks to settle
692 //udelay(0.01);
693
694 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
Felix Held9fe248f2018-07-31 20:59:45 +0200695 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100696
697 // Write reset using a NOP
698 write_reset(ctrl);
699 }
700}
701
702static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
703{
704 /* Get ODT based on rankmap: */
705 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
706 + ((ctrl->rankmap[channel] >> 2) & 1);
707
708 if (dimms_per_ch == 1) {
709 return (const odtmap){60, 60};
710 } else {
711 return (const odtmap){120, 30};
712 }
713}
714
715static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
716 int reg, u32 val)
717{
718 wait_428c(channel);
719
720 if (ctrl->rank_mirror[channel][slotrank]) {
721 /* DDR3 Rank1 Address mirror
722 * swap the following pins:
723 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
724 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
725 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
726 | ((val & 0xa8) << 1);
727 }
728
729 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200730 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
731 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
732 MCHBAR32(0x4200 + 0x400 * channel) =
733 (slotrank << 24) | (reg << 20) | val | 0x60000;
734 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100735
736 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200737 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
738 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
739 MCHBAR32(0x4204 + 0x400 * channel) =
740 (slotrank << 24) | (reg << 20) | val | 0x60000;
741 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100742
743 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200744 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
745 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
746 MCHBAR32(0x4208 + 0x400 * channel) =
747 (slotrank << 24) | (reg << 20) | val | 0x60000;
748 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200749
750 // execute command queue
751 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100752}
753
754static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
755{
756 u16 mr0reg, mch_cas, mch_wr;
757 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 +0100758 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100759
760 /* DLL Reset - self clearing - set after CLK frequency has been changed */
761 mr0reg = 0x100;
762
763 // Convert CAS to MCH register friendly
764 if (ctrl->CAS < 12) {
765 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
766 } else {
767 mch_cas = (u16) (ctrl->CAS - 12);
768 mch_cas = ((mch_cas << 1) | 0x1);
769 }
770
771 // Convert tWR to MCH register friendly
772 mch_wr = mch_wr_t[ctrl->tWR - 5];
773
774 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
775 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
776 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
777
778 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100779 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100780 return mr0reg;
781}
782
783static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
784{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200785 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100786}
787
788static u32 encode_odt(u32 odt)
789{
790 switch (odt) {
791 case 30:
792 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
793 case 60:
794 return (1 << 2); // RZQ/4
795 case 120:
796 return (1 << 6); // RZQ/2
797 default:
798 case 0:
799 return 0;
800 }
801}
802
803static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
804{
805 odtmap odt;
806 u32 mr1reg;
807
808 odt = get_ODT(ctrl, rank, channel);
809 mr1reg = 0x2;
810
811 mr1reg |= encode_odt(odt.rttnom);
812
813 return mr1reg;
814}
815
816static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
817{
818 u16 mr1reg;
819
820 mr1reg = make_mr1(ctrl, rank, channel);
821
822 write_mrreg(ctrl, channel, rank, 1, mr1reg);
823}
824
825static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
826{
827 u16 pasr, cwl, mr2reg;
828 odtmap odt;
829 int srt;
830
831 pasr = 0;
832 cwl = ctrl->CWL - 5;
833 odt = get_ODT(ctrl, rank, channel);
834
835 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
836
837 mr2reg = 0;
838 mr2reg = (mr2reg & ~0x7) | pasr;
839 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
840 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
841 mr2reg = (mr2reg & ~0x80) | (srt << 7);
842 mr2reg |= (odt.rttwr / 60) << 9;
843
844 write_mrreg(ctrl, channel, rank, 2, mr2reg);
845}
846
847static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
848{
849 write_mrreg(ctrl, channel, rank, 3, 0);
850}
851
852void dram_mrscommands(ramctr_timing * ctrl)
853{
854 u8 slotrank;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100855 int channel;
856
857 FOR_ALL_POPULATED_CHANNELS {
858 FOR_ALL_POPULATED_RANKS {
859 // MR2
860 dram_mr2(ctrl, slotrank, channel);
861
862 // MR3
863 dram_mr3(ctrl, slotrank, channel);
864
865 // MR1
866 dram_mr1(ctrl, slotrank, channel);
867
868 // MR0
869 dram_mr0(ctrl, slotrank, channel);
870 }
871 }
872
873 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200874 MCHBAR32(0x4e20) = 0x7;
875 MCHBAR32(0x4e30) = 0xf1001;
876 MCHBAR32(0x4e00) = 0x60002;
877 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100878
879 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200880 MCHBAR32(0x4e24) = 0x1f003;
881 MCHBAR32(0x4e34) = 0x1901001;
882 MCHBAR32(0x4e04) = 0x60400;
883 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100884
Felix Held9cf1dd22018-07-31 14:52:40 +0200885 // execute command queue on all channels? Why isn't bit 0 set here?
Felix Held2bb3cdf2018-07-28 00:23:59 +0200886 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100887
888 // Drain
889 FOR_ALL_CHANNELS {
890 // Wait for ref drained
891 wait_428c(channel);
892 }
893
894 // Refresh enable
Felix Held9fe248f2018-07-31 20:59:45 +0200895 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100896
897 FOR_ALL_POPULATED_CHANNELS {
Felix Held9fe248f2018-07-31 20:59:45 +0200898 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100899
900 wait_428c(channel);
901
902 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
903
904 // Drain
905 wait_428c(channel);
906
907 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200908 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
909 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
910 MCHBAR32(0x4200 + 0x400 * channel) =
911 (slotrank << 24) | 0x60000;
912 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200913
914 // execute command queue
915 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100916
917 // Drain
918 wait_428c(channel);
919 }
920}
921
922static const u32 lane_registers[] = {
923 0x0000, 0x0200, 0x0400, 0x0600,
924 0x1000, 0x1200, 0x1400, 0x1600,
925 0x0800
926};
927
928void program_timings(ramctr_timing * ctrl, int channel)
929{
930 u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028;
931 int lane;
932 int slotrank, slot;
933 int full_shift = 0;
934 u16 slot320c[NUM_SLOTS];
935
936 FOR_ALL_POPULATED_RANKS {
937 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
938 full_shift = -ctrl->timings[channel][slotrank].val_320c;
939 }
940
941 for (slot = 0; slot < NUM_SLOTS; slot++)
942 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
943 case 0:
944 default:
945 slot320c[slot] = 0x7f;
946 break;
947 case 1:
948 slot320c[slot] =
949 ctrl->timings[channel][2 * slot + 0].val_320c +
950 full_shift;
951 break;
952 case 2:
953 slot320c[slot] =
954 ctrl->timings[channel][2 * slot + 1].val_320c +
955 full_shift;
956 break;
957 case 3:
958 slot320c[slot] =
959 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200960 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100961 full_shift;
962 break;
963 }
964
965 /* enable CMD XOVER */
966 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
967 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
968 reg32 |= (slot320c[1] & 0x7f) << 18;
969 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
970
971 MCHBAR32(0x320c + 0x100 * channel) = reg32;
972
973 /* enable CLK XOVER */
974 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
975 reg_c18 = 0;
976
977 FOR_ALL_POPULATED_RANKS {
978 int shift =
979 ctrl->timings[channel][slotrank].val_320c + full_shift;
980 int offset_val_c14;
981 if (shift < 0)
982 shift = 0;
983 offset_val_c14 = ctrl->reg_c14_offset + shift;
984 /* set CLK phase shift */
985 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
986 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
987 }
988
989 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
990 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
991
992 reg_4028 = MCHBAR32(0x4028 + 0x400 * channel);
993 reg_4028 &= 0xffff0000;
994
995 reg_4024 = 0;
996
997 FOR_ALL_POPULATED_RANKS {
998 int post_timA_min_high = 7, post_timA_max_high = 0;
999 int pre_timA_min_high = 7, pre_timA_max_high = 0;
1000 int shift_402x = 0;
1001 int shift =
1002 ctrl->timings[channel][slotrank].val_320c + full_shift;
1003
1004 if (shift < 0)
1005 shift = 0;
1006
1007 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001008 post_timA_min_high = MIN(post_timA_min_high,
1009 (ctrl->timings[channel][slotrank].lanes[lane].
1010 timA + shift) >> 6);
1011 pre_timA_min_high = MIN(pre_timA_min_high,
1012 ctrl->timings[channel][slotrank].lanes[lane].
1013 timA >> 6);
1014 post_timA_max_high = MAX(post_timA_max_high,
1015 (ctrl->timings[channel][slotrank].lanes[lane].
1016 timA + shift) >> 6);
1017 pre_timA_max_high = MAX(pre_timA_max_high,
1018 ctrl->timings[channel][slotrank].lanes[lane].
1019 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001020 }
1021
1022 if (pre_timA_max_high - pre_timA_min_high <
1023 post_timA_max_high - post_timA_min_high)
1024 shift_402x = +1;
1025 else if (pre_timA_max_high - pre_timA_min_high >
1026 post_timA_max_high - post_timA_min_high)
1027 shift_402x = -1;
1028
1029 reg_4028 |=
1030 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1031 post_timA_min_high) << (4 * slotrank);
1032 reg_4024 |=
1033 (ctrl->timings[channel][slotrank].val_4024 +
1034 shift_402x) << (8 * slotrank);
1035
1036 FOR_ALL_LANES {
1037 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1038 4 * slotrank)
1039 =
1040 (((ctrl->timings[channel][slotrank].lanes[lane].
1041 timA + shift) & 0x3f)
1042 |
1043 ((ctrl->timings[channel][slotrank].lanes[lane].
1044 rising + shift) << 8)
1045 |
1046 (((ctrl->timings[channel][slotrank].lanes[lane].
1047 timA + shift -
1048 (post_timA_min_high << 6)) & 0x1c0) << 10)
1049 | ((ctrl->timings[channel][slotrank].lanes[lane].
1050 falling + shift) << 20));
1051
1052 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1053 4 * slotrank)
1054 =
1055 (((ctrl->timings[channel][slotrank].lanes[lane].
1056 timC + shift) & 0x3f)
1057 |
1058 (((ctrl->timings[channel][slotrank].lanes[lane].
1059 timB + shift) & 0x3f) << 8)
1060 |
1061 (((ctrl->timings[channel][slotrank].lanes[lane].
1062 timB + shift) & 0x1c0) << 9)
1063 |
1064 (((ctrl->timings[channel][slotrank].lanes[lane].
1065 timC + shift) & 0x40) << 13));
1066 }
1067 }
1068 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
1069 MCHBAR32(0x4028 + 0x400 * channel) = reg_4028;
1070}
1071
1072static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1073{
1074 wait_428c(channel);
1075
1076 /* DRAM command MRS
1077 * write MR3 MPR enable
1078 * in this mode only RD and RDA are allowed
1079 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001080 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1081 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1082 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1083 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001084
1085 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001086 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1087 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1088 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1089 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001090
1091 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001092 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1093 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1094 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1095 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001096
1097 /* DRAM command MRS
1098 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001099 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1100 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1101 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1102 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001103
Felix Held9cf1dd22018-07-31 14:52:40 +02001104 // execute command queue
1105 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001106
1107 wait_428c(channel);
1108}
1109
1110static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1111 int lane)
1112{
1113 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001114 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001115 ((timA / 32) & 1) * 4)
1116 >> (timA % 32)) & 1);
1117}
1118
1119struct run {
1120 int middle;
1121 int end;
1122 int start;
1123 int all;
1124 int length;
1125};
1126
1127static struct run get_longest_zero_run(int *seq, int sz)
1128{
1129 int i, ls;
1130 int bl = 0, bs = 0;
1131 struct run ret;
1132
1133 ls = 0;
1134 for (i = 0; i < 2 * sz; i++)
1135 if (seq[i % sz]) {
1136 if (i - ls > bl) {
1137 bl = i - ls;
1138 bs = ls;
1139 }
1140 ls = i + 1;
1141 }
1142 if (bl == 0) {
1143 ret.middle = sz / 2;
1144 ret.start = 0;
1145 ret.end = sz;
Jacob Garbere0c181d2019-04-08 22:21:43 -06001146 ret.length = sz;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001147 ret.all = 1;
1148 return ret;
1149 }
1150
1151 ret.start = bs % sz;
1152 ret.end = (bs + bl - 1) % sz;
1153 ret.middle = (bs + (bl - 1) / 2) % sz;
1154 ret.length = bl;
1155 ret.all = 0;
1156
1157 return ret;
1158}
1159
1160static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1161 int slotrank, int *upperA)
1162{
1163 int timA;
1164 int statistics[NUM_LANES][128];
1165 int lane;
1166
1167 for (timA = 0; timA < 128; timA++) {
1168 FOR_ALL_LANES {
1169 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1170 }
1171 program_timings(ctrl, channel);
1172
1173 test_timA(ctrl, channel, slotrank);
1174
1175 FOR_ALL_LANES {
1176 statistics[lane][timA] =
1177 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001178 }
1179 }
1180 FOR_ALL_LANES {
1181 struct run rn = get_longest_zero_run(statistics[lane], 128);
1182 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1183 upperA[lane] = rn.end;
1184 if (upperA[lane] < rn.middle)
1185 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001186 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001187 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001188 }
1189}
1190
1191static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1192 int *upperA)
1193{
1194 int timA_delta;
1195 int statistics[NUM_LANES][51];
1196 int lane, i;
1197
1198 memset(statistics, 0, sizeof(statistics));
1199
1200 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1201 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1202 timA = upperA[lane] + timA_delta + 0x40;
1203 program_timings(ctrl, channel);
1204
1205 for (i = 0; i < 100; i++) {
1206 test_timA(ctrl, channel, slotrank);
1207 FOR_ALL_LANES {
1208 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001209 does_lane_work(ctrl, channel, slotrank,
1210 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001211 }
1212 }
1213 }
1214 FOR_ALL_LANES {
1215 int last_zero, first_all;
1216
1217 for (last_zero = -25; last_zero <= 25; last_zero++)
1218 if (statistics[lane][last_zero + 25])
1219 break;
1220 last_zero--;
1221 for (first_all = -25; first_all <= 25; first_all++)
1222 if (statistics[lane][first_all + 25] == 100)
1223 break;
1224
1225 printram("lane %d: %d, %d\n", lane, last_zero,
1226 first_all);
1227
1228 ctrl->timings[channel][slotrank].lanes[lane].timA =
1229 (last_zero + first_all) / 2 + upperA[lane];
1230 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1231 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1232 }
1233}
1234
1235static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1236 int *upperA)
1237{
1238 int works[NUM_LANES];
1239 int lane;
1240 while (1) {
1241 int all_works = 1, some_works = 0;
1242 program_timings(ctrl, channel);
1243 test_timA(ctrl, channel, slotrank);
1244 FOR_ALL_LANES {
1245 works[lane] =
1246 !does_lane_work(ctrl, channel, slotrank, lane);
1247 if (works[lane])
1248 some_works = 1;
1249 else
1250 all_works = 0;
1251 }
1252 if (all_works)
1253 return 0;
1254 if (!some_works) {
1255 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1256 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1257 channel, slotrank);
1258 return MAKE_ERR;
1259 }
1260 ctrl->timings[channel][slotrank].val_4024 -= 2;
1261 printram("4024 -= 2;\n");
1262 continue;
1263 }
1264 ctrl->timings[channel][slotrank].val_4028 += 2;
1265 printram("4028 += 2;\n");
1266 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1267 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1268 channel, slotrank);
1269 return MAKE_ERR;
1270 }
1271 FOR_ALL_LANES if (works[lane]) {
1272 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1273 128;
1274 upperA[lane] += 128;
1275 printram("increment %d, %d, %d\n", channel,
1276 slotrank, lane);
1277 }
1278 }
1279 return 0;
1280}
1281
1282struct timA_minmax {
1283 int timA_min_high, timA_max_high;
1284};
1285
1286static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1287 struct timA_minmax *mnmx)
1288{
1289 int lane;
1290 mnmx->timA_min_high = 7;
1291 mnmx->timA_max_high = 0;
1292
1293 FOR_ALL_LANES {
1294 if (mnmx->timA_min_high >
1295 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1296 mnmx->timA_min_high =
1297 (ctrl->timings[channel][slotrank].lanes[lane].
1298 timA >> 6);
1299 if (mnmx->timA_max_high <
1300 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1301 mnmx->timA_max_high =
1302 (ctrl->timings[channel][slotrank].lanes[lane].
1303 timA >> 6);
1304 }
1305}
1306
1307static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1308 struct timA_minmax *mnmx)
1309{
1310 struct timA_minmax post;
1311 int shift_402x = 0;
1312
1313 /* Get changed maxima. */
1314 pre_timA_change(ctrl, channel, slotrank, &post);
1315
1316 if (mnmx->timA_max_high - mnmx->timA_min_high <
1317 post.timA_max_high - post.timA_min_high)
1318 shift_402x = +1;
1319 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1320 post.timA_max_high - post.timA_min_high)
1321 shift_402x = -1;
1322 else
1323 shift_402x = 0;
1324
1325 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1326 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1327 printram("4024 += %d;\n", shift_402x);
1328 printram("4028 += %d;\n", shift_402x);
1329}
1330
1331/* Compensate the skew between DQS and DQs.
1332 * To ease PCB design a small skew between Data Strobe signals and
1333 * Data Signals is allowed.
1334 * The controller has to measure and compensate this skew for every byte-lane.
1335 * By delaying either all DQs signals or DQS signal, a full phase
1336 * shift can be introduced.
1337 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1338 *
1339 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1340 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1341 * The memory controller iterates over all possible values to do a full phase shift
1342 * and issues read commands.
1343 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1344 * 0xFF 0x00 0xFF ...
1345 * Once the controller has detected this pattern a bit in the result register is
1346 * set for the current phase shift.
1347 */
1348int read_training(ramctr_timing * ctrl)
1349{
1350 int channel, slotrank, lane;
1351 int err;
1352
1353 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1354 int all_high, some_high;
1355 int upperA[NUM_LANES];
1356 struct timA_minmax mnmx;
1357
Felix Held2bb3cdf2018-07-28 00:23:59 +02001358 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001359
Felix Held2bb3cdf2018-07-28 00:23:59 +02001360 /* DRAM command PREA */
1361 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1362 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1363 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1364 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001365
1366 // execute command queue
1367 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001368
Felix Held2bb3cdf2018-07-28 00:23:59 +02001369 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001370
Felix Held2bb3cdf2018-07-28 00:23:59 +02001371 ctrl->timings[channel][slotrank].val_4028 = 4;
1372 ctrl->timings[channel][slotrank].val_4024 = 55;
1373 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001374
Felix Held2bb3cdf2018-07-28 00:23:59 +02001375 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001376
Felix Held2bb3cdf2018-07-28 00:23:59 +02001377 all_high = 1;
1378 some_high = 0;
1379 FOR_ALL_LANES {
1380 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1381 0x40)
1382 some_high = 1;
1383 else
1384 all_high = 0;
1385 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001386
1387 if (all_high) {
1388 ctrl->timings[channel][slotrank].val_4028--;
1389 printram("4028--;\n");
1390 FOR_ALL_LANES {
1391 ctrl->timings[channel][slotrank].lanes[lane].
1392 timA -= 0x40;
1393 upperA[lane] -= 0x40;
1394
1395 }
1396 } else if (some_high) {
1397 ctrl->timings[channel][slotrank].val_4024++;
1398 ctrl->timings[channel][slotrank].val_4028++;
1399 printram("4024++;\n");
1400 printram("4028++;\n");
1401 }
1402
1403 program_timings(ctrl, channel);
1404
1405 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1406
1407 err = discover_402x(ctrl, channel, slotrank, upperA);
1408 if (err)
1409 return err;
1410
1411 post_timA_change(ctrl, channel, slotrank, &mnmx);
1412 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1413
1414 discover_timA_fine(ctrl, channel, slotrank, upperA);
1415
1416 post_timA_change(ctrl, channel, slotrank, &mnmx);
1417 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1418
1419 FOR_ALL_LANES {
1420 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1421 }
1422 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1423 printram("4028 -= %d;\n", mnmx.timA_min_high);
1424
1425 post_timA_change(ctrl, channel, slotrank, &mnmx);
1426
1427 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1428 ctrl->timings[channel][slotrank].val_4024,
1429 ctrl->timings[channel][slotrank].val_4028);
1430
1431 printram("final results:\n");
1432 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001433 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1434 lane,
1435 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001436
Felix Held2bb3cdf2018-07-28 00:23:59 +02001437 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001438
1439 toggle_io_reset();
1440 }
1441
1442 FOR_ALL_POPULATED_CHANNELS {
1443 program_timings(ctrl, channel);
1444 }
1445 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001446 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001447 }
1448 return 0;
1449}
1450
1451static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1452{
1453 int lane;
1454
1455 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001456 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02001457 MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001458 }
1459
1460 wait_428c(channel);
1461
1462 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001463 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1464 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001465 (MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001466 | 4 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001467 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001468 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001469
1470 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001471 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1472 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1473 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1474 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001475
1476 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001477 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1478 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1479 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1480 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001481
1482 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001483 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1484 MCHBAR32(0x423c + 0x400 * channel) =
1485 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1486 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1487 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001488
Felix Held9cf1dd22018-07-31 14:52:40 +02001489 // execute command queue
1490 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001491
1492 wait_428c(channel);
1493
1494 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001495 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1496 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1497 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1498 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001499
1500 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001501 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1502 MCHBAR32(0x4234 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001503 (MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001504 | 8 | (ctrl->CAS << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001505 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001506 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001507
1508 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001509 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1510 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001511 0x40011f4 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001512 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1513 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001514
1515 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001516 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1517 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1518 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1519 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001520
1521 // execute command queue
1522 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1523
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001524 wait_428c(channel);
1525}
1526
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001527static void timC_threshold_process(int *data, const int count)
1528{
1529 int min = data[0];
1530 int max = min;
1531 int i;
1532 for (i = 1; i < count; i++) {
1533 if (min > data[i])
1534 min = data[i];
1535 if (max < data[i])
1536 max = data[i];
1537 }
1538 int threshold = min/2 + max/2;
1539 for (i = 0; i < count; i++)
1540 data[i] = data[i] > threshold;
1541 printram("threshold=%d min=%d max=%d\n",
1542 threshold, min, max);
1543}
1544
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001545static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1546{
1547 int timC;
1548 int statistics[NUM_LANES][MAX_TIMC + 1];
1549 int lane;
1550
1551 wait_428c(channel);
1552
1553 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001554 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1555 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
Felix Held9fe248f2018-07-31 20:59:45 +02001556 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001557 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001558
1559 // execute command queue
1560 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001561
1562 for (timC = 0; timC <= MAX_TIMC; timC++) {
1563 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1564 timC = timC;
1565 program_timings(ctrl, channel);
1566
1567 test_timC(ctrl, channel, slotrank);
1568
1569 FOR_ALL_LANES {
1570 statistics[lane][timC] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001571 MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001572 }
1573 }
1574 FOR_ALL_LANES {
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001575 struct run rn = get_longest_zero_run(
1576 statistics[lane], ARRAY_SIZE(statistics[lane]));
1577 if (rn.all || rn.length < 8) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001578 printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
1579 channel, slotrank, lane);
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001580 /* With command training not happend yet, the lane can
1581 * be erroneous. Take the avarage as reference and try
1582 * again to find a run.
1583 */
1584 timC_threshold_process(statistics[lane],
1585 ARRAY_SIZE(statistics[lane]));
1586 rn = get_longest_zero_run(statistics[lane],
1587 ARRAY_SIZE(statistics[lane]));
1588 if (rn.all || rn.length < 8) {
1589 printk(BIOS_EMERG, "timC recovery failed\n");
1590 return MAKE_ERR;
1591 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001592 }
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001593 ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001594 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001595 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001596 }
1597 return 0;
1598}
1599
1600static int get_precedening_channels(ramctr_timing * ctrl, int target_channel)
1601{
1602 int channel, ret = 0;
1603 FOR_ALL_POPULATED_CHANNELS if (channel < target_channel)
1604 ret++;
1605 return ret;
1606}
1607
1608static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b)
1609{
Subrata Banikb1434fc2019-03-15 22:20:41 +05301610 unsigned int j;
1611 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001612 get_precedening_channels(ctrl, channel) * 0x40;
1613 for (j = 0; j < 16; j++)
1614 write32((void *)(0x04000000 + channel_offset + 4 * j), j & 2 ? b : a);
1615 sfence();
1616}
1617
1618static int num_of_channels(const ramctr_timing * ctrl)
1619{
1620 int ret = 0;
1621 int channel;
1622 FOR_ALL_POPULATED_CHANNELS ret++;
1623 return ret;
1624}
1625
1626static void fill_pattern1(ramctr_timing * ctrl, int channel)
1627{
Subrata Banikb1434fc2019-03-15 22:20:41 +05301628 unsigned int j;
1629 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001630 get_precedening_channels(ctrl, channel) * 0x40;
Subrata Banikb1434fc2019-03-15 22:20:41 +05301631 unsigned int channel_step = 0x40 * num_of_channels(ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001632 for (j = 0; j < 16; j++)
1633 write32((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff);
1634 for (j = 0; j < 16; j++)
1635 write32((void *)(0x04000000 + channel_offset + channel_step + j * 4), 0);
1636 sfence();
1637}
1638
1639static void precharge(ramctr_timing * ctrl)
1640{
1641 int channel, slotrank, lane;
1642
1643 FOR_ALL_POPULATED_CHANNELS {
1644 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1645 ctrl->timings[channel][slotrank].lanes[lane].falling =
1646 16;
1647 ctrl->timings[channel][slotrank].lanes[lane].rising =
1648 16;
1649 }
1650
1651 program_timings(ctrl, channel);
1652
1653 FOR_ALL_POPULATED_RANKS {
1654 wait_428c(channel);
1655
1656 /* DRAM command MRS
1657 * write MR3 MPR enable
1658 * in this mode only RD and RDA are allowed
1659 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001660 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1661 MCHBAR32(0x4230 + 0x400 * channel) =
1662 0xc01 | (ctrl->tMOD << 16);
1663 MCHBAR32(0x4200 + 0x400 * channel) =
1664 (slotrank << 24) | 0x360004;
1665 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001666
1667 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001668 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1669 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1670 MCHBAR32(0x4204 + 0x400 * channel) =
1671 (slotrank << 24) | 0;
1672 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001673
1674 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001675 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1676 MCHBAR32(0x4238 + 0x400 * channel) =
1677 0x1001 | ((ctrl->CAS + 8) << 16);
1678 MCHBAR32(0x4208 + 0x400 * channel) =
1679 (slotrank << 24) | 0x60000;
1680 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001681
1682 /* DRAM command MRS
1683 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001684 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1685 MCHBAR32(0x423c + 0x400 * channel) =
1686 0xc01 | (ctrl->tMOD << 16);
1687 MCHBAR32(0x420c + 0x400 * channel) =
1688 (slotrank << 24) | 0x360000;
1689 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001690
1691 // execute command queue
1692 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001693
1694 wait_428c(channel);
1695 }
1696
1697 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1698 ctrl->timings[channel][slotrank].lanes[lane].falling =
1699 48;
1700 ctrl->timings[channel][slotrank].lanes[lane].rising =
1701 48;
1702 }
1703
1704 program_timings(ctrl, channel);
1705
1706 FOR_ALL_POPULATED_RANKS {
1707 wait_428c(channel);
1708 /* DRAM command MRS
1709 * write MR3 MPR enable
1710 * in this mode only RD and RDA are allowed
1711 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001712 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1713 MCHBAR32(0x4230 + 0x400 * channel) =
1714 0xc01 | (ctrl->tMOD << 16);
1715 MCHBAR32(0x4200 + 0x400 * channel) =
1716 (slotrank << 24) | 0x360004;
1717 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001718
1719 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001720 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1721 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1722 MCHBAR32(0x4204 + 0x400 * channel) =
1723 (slotrank << 24) | 0;
1724 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001725
1726 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001727 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1728 MCHBAR32(0x4238 + 0x400 * channel) =
1729 0x1001 | ((ctrl->CAS + 8) << 16);
1730 MCHBAR32(0x4208 + 0x400 * channel) =
1731 (slotrank << 24) | 0x60000;
1732 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001733
1734 /* DRAM command MRS
1735 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001736 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1737 MCHBAR32(0x423c + 0x400 * channel) =
1738 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001739 MCHBAR32(0x420c + 0x400 * channel) =
1740 (slotrank << 24) | 0x360000;
1741 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001742
Felix Held9cf1dd22018-07-31 14:52:40 +02001743 // execute command queue
1744 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1745
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001746 wait_428c(channel);
1747 }
1748 }
1749}
1750
1751static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1752{
1753 /* enable DQs on this slotrank */
1754 write_mrreg(ctrl, channel, slotrank, 1,
1755 0x80 | make_mr1(ctrl, slotrank, channel));
1756
1757 wait_428c(channel);
1758 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001759 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1760 MCHBAR32(0x4230 + 0x400 * channel) =
1761 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1762 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1763 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001764
1765 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001766 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1767 MCHBAR32(0x4234 + 0x400 * channel) =
1768 0x4000c01 | ((ctrl->CAS + 38) << 16);
1769 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1770 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001771
Felix Held9cf1dd22018-07-31 14:52:40 +02001772 // execute command queue
1773 MCHBAR32(0x400 * channel + 0x4284) = RUN_QUEUE_4284(2);
1774
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001775 wait_428c(channel);
1776
1777 /* disable DQs on this slotrank */
1778 write_mrreg(ctrl, channel, slotrank, 1,
1779 0x1080 | make_mr1(ctrl, slotrank, channel));
1780}
1781
1782static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1783{
1784 int timB;
1785 int statistics[NUM_LANES][128];
1786 int lane;
1787
Felix Held2bb3cdf2018-07-28 00:23:59 +02001788 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001789
1790 for (timB = 0; timB < 128; timB++) {
1791 FOR_ALL_LANES {
1792 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1793 }
1794 program_timings(ctrl, channel);
1795
1796 test_timB(ctrl, channel, slotrank);
1797
1798 FOR_ALL_LANES {
1799 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001800 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001801 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1802 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001803 }
1804 }
1805 FOR_ALL_LANES {
1806 struct run rn = get_longest_zero_run(statistics[lane], 128);
1807 /* timC is a direct function of timB's 6 LSBs.
1808 * Some tests increments the value of timB by a small value,
1809 * which might cause the 6bit value to overflow, if it's close
1810 * to 0x3F. Increment the value by a small offset if it's likely
1811 * to overflow, to make sure it won't overflow while running
1812 * tests and bricks the system due to a non matching timC.
1813 *
1814 * TODO: find out why some tests (edge write discovery)
1815 * increment timB. */
1816 if ((rn.start & 0x3F) == 0x3E)
1817 rn.start += 2;
1818 else if ((rn.start & 0x3F) == 0x3F)
1819 rn.start += 1;
1820 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1821 if (rn.all) {
1822 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1823 channel, slotrank, lane);
1824 return MAKE_ERR;
1825 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001826 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1827 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001828 }
1829 return 0;
1830}
1831
1832static int get_timB_high_adjust(u64 val)
1833{
1834 int i;
1835
1836 /* good */
1837 if (val == 0xffffffffffffffffLL)
1838 return 0;
1839
1840 if (val >= 0xf000000000000000LL) {
1841 /* needs negative adjustment */
1842 for (i = 0; i < 8; i++)
1843 if (val << (8 * (7 - i) + 4))
1844 return -i;
1845 } else {
1846 /* needs positive adjustment */
1847 for (i = 0; i < 8; i++)
1848 if (val >> (8 * (7 - i) + 4))
1849 return i;
1850 }
1851 return 8;
1852}
1853
1854static void adjust_high_timB(ramctr_timing * ctrl)
1855{
1856 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001857 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001858 FOR_ALL_POPULATED_CHANNELS {
1859 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001860 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001861 }
1862 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1863
Felix Held2bb3cdf2018-07-28 00:23:59 +02001864 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001865
1866 wait_428c(channel);
1867
1868 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001869 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1870 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1871 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1872 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001873
1874 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001875 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1876 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1877 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1878 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001879
1880 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001881 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1882 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1883 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1884 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001885
1886 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001887 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1888 MCHBAR32(0x423c + 0x400 * channel) =
1889 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1890 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1891 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001892
Felix Held9cf1dd22018-07-31 14:52:40 +02001893 // execute command queue
1894 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001895
1896 wait_428c(channel);
1897
1898 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001899 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1900 MCHBAR32(0x4230 + 0x400 * channel) =
1901 0xc01 | ((ctrl->tRP) << 16);
1902 MCHBAR32(0x4200 + 0x400 * channel) =
1903 (slotrank << 24) | 0x60400;
1904 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001905
1906 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001907 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1908 MCHBAR32(0x4234 + 0x400 * channel) =
1909 0xc01 | ((ctrl->tRCD) << 16);
1910 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1911 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001912
1913 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001914 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1915 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001916 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001917 ctrl->timings[channel][slotrank].val_4028) << 16);
1918 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1919 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001920
Felix Held9cf1dd22018-07-31 14:52:40 +02001921 // execute command queue
1922 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
1923
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001924 wait_428c(channel);
1925 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001926 u64 res = MCHBAR32(lane_registers[lane] +
1927 0x100 * channel + 4);
1928 res |= ((u64) MCHBAR32(lane_registers[lane] +
1929 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001930 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1931 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1932 get_timB_high_adjust(res) * 64;
1933
1934 printram("High adjust %d:%016llx\n", lane, res);
1935 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1936 slotrank, lane, old,
1937 ctrl->timings[channel][slotrank].lanes[lane].
1938 timB);
1939 }
1940 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001941 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001942}
1943
1944static void write_op(ramctr_timing * ctrl, int channel)
1945{
1946 int slotrank;
1947
1948 wait_428c(channel);
1949
1950 /* choose an existing rank. */
1951 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1952
1953 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001954 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1955 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001956 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001957 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001958
Felix Held9cf1dd22018-07-31 14:52:40 +02001959 // execute command queue
1960 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
1961
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001962 wait_428c(channel);
1963}
1964
1965/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1966 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1967 * the chips at different times with respect to command, address and
1968 * clock signals.
1969 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1970 * shift can be introduced.
1971 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1972 *
1973 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1974 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1975 * sampled value on the data lanes (DQs).
1976 */
1977int write_training(ramctr_timing * ctrl)
1978{
1979 int channel, slotrank, lane;
1980 int err;
1981
1982 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001983 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001984
1985 FOR_ALL_POPULATED_CHANNELS {
1986 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001987 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001988 }
1989
1990 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001991 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001992 FOR_ALL_POPULATED_CHANNELS {
1993 write_op(ctrl, channel);
1994 }
1995
1996 /* enable write leveling on all ranks
1997 * disable all DQ outputs
1998 * only NOP is allowed in this mode */
1999 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002000 FOR_ALL_POPULATED_RANKS
2001 write_mrreg(ctrl, channel, slotrank, 1,
2002 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002003
Felix Held2bb3cdf2018-07-28 00:23:59 +02002004 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002005
2006 toggle_io_reset();
2007
2008 /* set any valid value for timB, it gets corrected later */
2009 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2010 err = discover_timB(ctrl, channel, slotrank);
2011 if (err)
2012 return err;
2013 }
2014
2015 /* disable write leveling on all ranks */
2016 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
2017 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002018 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002019
Felix Held2bb3cdf2018-07-28 00:23:59 +02002020 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002021
2022 FOR_ALL_POPULATED_CHANNELS
2023 wait_428c(channel);
2024
2025 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02002026 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002027
2028 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002029 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002030 MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002031 wait_428c(channel);
2032
2033 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002034 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2035 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2036 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2037 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002038
Felix Held9cf1dd22018-07-31 14:52:40 +02002039 // execute command queue
2040 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2041
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002042 wait_428c(channel);
2043 }
2044
2045 toggle_io_reset();
2046
2047 printram("CPE\n");
2048 precharge(ctrl);
2049 printram("CPF\n");
2050
2051 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002052 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002053 }
2054
2055 FOR_ALL_POPULATED_CHANNELS {
2056 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002057 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002058 }
2059
2060 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2061 err = discover_timC(ctrl, channel, slotrank);
2062 if (err)
2063 return err;
2064 }
2065
2066 FOR_ALL_POPULATED_CHANNELS
2067 program_timings(ctrl, channel);
2068
2069 /* measure and adjust timB timings */
2070 adjust_high_timB(ctrl);
2071
2072 FOR_ALL_POPULATED_CHANNELS
2073 program_timings(ctrl, channel);
2074
2075 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002076 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002077 }
2078 return 0;
2079}
2080
2081static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2082{
2083 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2084 int timC_delta;
2085 int lanes_ok = 0;
2086 int ctr = 0;
2087 int lane;
2088
2089 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2090 FOR_ALL_LANES {
2091 ctrl->timings[channel][slotrank].lanes[lane].timC =
2092 saved_rt.lanes[lane].timC + timC_delta;
2093 }
2094 program_timings(ctrl, channel);
2095 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002096 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002097 }
2098
Felix Held2bb3cdf2018-07-28 00:23:59 +02002099 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002100
2101 wait_428c(channel);
2102 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002103 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2104 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002105 ((MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002106 | 8 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002107 MCHBAR32(0x4200 + 0x400 * channel) =
2108 (slotrank << 24) | ctr | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002109 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Felix Held9fe248f2018-07-31 20:59:45 +02002110
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002111 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002112 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2113 MCHBAR32(0x4234 + 0x400 * channel) =
2114 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2115 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2116 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2117 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002118
2119 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002120 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2121 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002122 0x4001020 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002123 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2124 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2125 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002126
2127 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002128 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2129 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2130 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2131 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002132
Felix Held9cf1dd22018-07-31 14:52:40 +02002133 // execute command queue
2134 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2135
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002136 wait_428c(channel);
2137 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002138 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002139
2140 if (r32 == 0)
2141 lanes_ok |= 1 << lane;
2142 }
2143 ctr++;
2144 if (lanes_ok == ((1 << NUM_LANES) - 1))
2145 break;
2146 }
2147
2148 ctrl->timings[channel][slotrank] = saved_rt;
2149
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002150 return lanes_ok != ((1 << NUM_LANES) - 1);
2151}
2152
2153#include "raminit_patterns.h"
2154
2155static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2156{
Subrata Banikb1434fc2019-03-15 22:20:41 +05302157 unsigned int i, j;
2158 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002159 get_precedening_channels(ctrl, channel) * 0x40;
Subrata Banikb1434fc2019-03-15 22:20:41 +05302160 unsigned int channel_step = 0x40 * num_of_channels(ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002161
2162 if (patno) {
2163 u8 base8 = 0x80 >> ((patno - 1) % 8);
2164 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2165 for (i = 0; i < 32; i++) {
2166 for (j = 0; j < 16; j++) {
2167 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2168 if (invert[patno - 1][i] & (1 << (j / 2)))
2169 val = ~val;
2170 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2171 j * 4), val);
2172 }
2173 }
2174
2175 } else {
2176 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2177 for (j = 0; j < 16; j++)
2178 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2179 j * 4), pattern[i][j]);
2180 }
2181 sfence();
2182 }
2183}
2184
2185static void reprogram_320c(ramctr_timing * ctrl)
2186{
2187 int channel, slotrank;
2188
2189 FOR_ALL_POPULATED_CHANNELS {
2190 wait_428c(channel);
2191
2192 /* choose an existing rank. */
2193 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2194
2195 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002196 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2197 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002198 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002199 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002200
Felix Held9cf1dd22018-07-31 14:52:40 +02002201 // execute command queue
2202 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2203
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002204 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002205 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002206 }
2207
2208 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002209 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002210 FOR_ALL_POPULATED_CHANNELS {
2211 wait_428c(channel);
2212
2213 /* choose an existing rank. */
2214 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2215
2216 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002217 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2218 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002219 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002220 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002221
Felix Held9cf1dd22018-07-31 14:52:40 +02002222 // execute command queue
2223 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2224
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002225 wait_428c(channel);
2226 }
2227
2228 /* jedec reset */
2229 dram_jedecreset(ctrl);
2230 /* mrs commands. */
2231 dram_mrscommands(ctrl);
2232
2233 toggle_io_reset();
2234}
2235
2236#define MIN_C320C_LEN 13
2237
2238static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2239{
2240 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2241 int slotrank;
2242 int c320c;
2243 int stat[NUM_SLOTRANKS][256];
2244 int delta = 0;
2245
2246 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2247
2248 FOR_ALL_POPULATED_RANKS {
2249 saved_timings[channel][slotrank] =
2250 ctrl->timings[channel][slotrank];
2251 }
2252
2253 ctrl->cmd_stretch[channel] = cmd_stretch;
2254
2255 MCHBAR32(0x4004 + 0x400 * channel) =
2256 ctrl->tRRD
2257 | (ctrl->tRTP << 4)
2258 | (ctrl->tCKE << 8)
2259 | (ctrl->tWTR << 12)
2260 | (ctrl->tFAW << 16)
2261 | (ctrl->tWR << 24)
2262 | (ctrl->cmd_stretch[channel] << 30);
2263
2264 if (ctrl->cmd_stretch[channel] == 2)
2265 delta = 2;
2266 else if (ctrl->cmd_stretch[channel] == 0)
2267 delta = 4;
2268
2269 FOR_ALL_POPULATED_RANKS {
2270 ctrl->timings[channel][slotrank].val_4024 -= delta;
2271 }
2272
2273 for (c320c = -127; c320c <= 127; c320c++) {
2274 FOR_ALL_POPULATED_RANKS {
2275 ctrl->timings[channel][slotrank].val_320c = c320c;
2276 }
2277 program_timings(ctrl, channel);
2278 reprogram_320c(ctrl);
2279 FOR_ALL_POPULATED_RANKS {
2280 stat[slotrank][c320c + 127] =
2281 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002282 }
2283 }
2284 FOR_ALL_POPULATED_RANKS {
2285 struct run rn =
2286 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002287 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002288 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2289 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002290 if (rn.all || rn.length < MIN_C320C_LEN) {
2291 FOR_ALL_POPULATED_RANKS {
2292 ctrl->timings[channel][slotrank] =
2293 saved_timings[channel][slotrank];
2294 }
2295 return MAKE_ERR;
2296 }
2297 }
2298
2299 return 0;
2300}
2301
2302/* Adjust CMD phase shift and try multiple command rates.
2303 * A command rate of 2T doubles the time needed for address and
2304 * command decode. */
2305int command_training(ramctr_timing *ctrl)
2306{
2307 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002308
2309 FOR_ALL_POPULATED_CHANNELS {
2310 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002311 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002312 }
2313
2314 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002315 int cmdrate, err;
2316
2317 /*
2318 * Dual DIMM per channel:
2319 * Issue: While c320c discovery seems to succeed raminit
2320 * will fail in write training.
2321 * Workaround: Skip 1T in dual DIMM mode, that's only
2322 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002323 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2324 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002325 *
2326 * Single DIMM per channel:
2327 * Try command rate 1T and 2T
2328 */
2329 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002330 if (ctrl->tCMD)
2331 /* XMP gives the CMD rate in clock ticks, not ns */
2332 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002333
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002334 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002335 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2336
2337 if (!err)
2338 break;
2339 }
2340
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002341 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002342 printk(BIOS_EMERG, "c320c discovery failed\n");
2343 return err;
2344 }
2345
2346 printram("Using CMD rate %uT on channel %u\n",
2347 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002348 }
2349
2350 FOR_ALL_POPULATED_CHANNELS
2351 program_timings(ctrl, channel);
2352
2353 reprogram_320c(ctrl);
2354 return 0;
2355}
2356
2357
2358static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2359 int *edges)
2360{
2361 int edge;
2362 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2363 int lane;
2364
2365 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2366 FOR_ALL_LANES {
2367 ctrl->timings[channel][slotrank].lanes[lane].rising =
2368 edge;
2369 ctrl->timings[channel][slotrank].lanes[lane].falling =
2370 edge;
2371 }
2372 program_timings(ctrl, channel);
2373
2374 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002375 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002376 MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002377 }
2378
2379 wait_428c(channel);
2380 /* DRAM command MRS
2381 * write MR3 MPR enable
2382 * in this mode only RD and RDA are allowed
2383 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002384 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002385 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002386 MCHBAR32(0x4200 + 0x400 * channel) =
2387 (slotrank << 24) | 0x360004;
2388 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002389
2390 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002391 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2392 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2393 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2394 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002395
2396 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002397 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2398 MCHBAR32(0x4238 + 0x400 * channel) =
2399 0x1001 | ((ctrl->CAS + 8) << 16);
2400 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2401 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002402
2403 /* DRAM command MRS
2404 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002405 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2406 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2407 MCHBAR32(0x420c + 0x400 * channel) =
2408 (slotrank << 24) | 0x360000;
2409 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002410
Felix Held9cf1dd22018-07-31 14:52:40 +02002411 // execute command queue
2412 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002413
2414 wait_428c(channel);
2415
2416 FOR_ALL_LANES {
2417 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002418 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002419 }
2420 }
2421 FOR_ALL_LANES {
2422 struct run rn =
2423 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2424 edges[lane] = rn.middle;
2425 if (rn.all) {
2426 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2427 channel, slotrank, lane);
2428 return MAKE_ERR;
2429 }
2430 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2431 lane, edges[lane]);
2432 }
2433 return 0;
2434}
2435
2436int discover_edges(ramctr_timing *ctrl)
2437{
2438 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2439 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2440 int channel, slotrank, lane;
2441 int err;
2442
Felix Held2bb3cdf2018-07-28 00:23:59 +02002443 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002444
2445 toggle_io_reset();
2446
2447 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002448 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002449 }
2450
2451 FOR_ALL_POPULATED_CHANNELS {
2452 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002453 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002454 FOR_ALL_LANES {
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002455 MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002456 }
2457
2458 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2459 ctrl->timings[channel][slotrank].lanes[lane].falling =
2460 16;
2461 ctrl->timings[channel][slotrank].lanes[lane].rising =
2462 16;
2463 }
2464
2465 program_timings(ctrl, channel);
2466
2467 FOR_ALL_POPULATED_RANKS {
2468 wait_428c(channel);
2469
2470 /* DRAM command MRS
2471 * MR3 enable MPR
2472 * write MR3 MPR enable
2473 * in this mode only RD and RDA are allowed
2474 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002475 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2476 MCHBAR32(0x4230 + 0x400 * channel) =
2477 0xc01 | (ctrl->tMOD << 16);
2478 MCHBAR32(0x4200 + 0x400 * channel) =
2479 (slotrank << 24) | 0x360004;
2480 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002481
2482 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002483 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2484 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2485 MCHBAR32(0x4204 + 0x400 * channel) =
2486 (slotrank << 24) | 0;
2487 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002488
2489 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002490 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2491 MCHBAR32(0x4238 + 0x400 * channel) =
2492 0x1001 | ((ctrl->CAS + 8) << 16);
2493 MCHBAR32(0x4208 + 0x400 * channel) =
2494 (slotrank << 24) | 0x60000;
2495 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002496
2497 /* DRAM command MRS
2498 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002499 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2500 MCHBAR32(0x423c + 0x400 * channel) =
2501 0xc01 | (ctrl->tMOD << 16);
2502 MCHBAR32(0x420c + 0x400 * channel) =
2503 (slotrank << 24) | 0x360000;
2504 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02002505
2506 // execute command queue
2507 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002508
2509 wait_428c(channel);
2510 }
2511
2512 /* XXX: check any measured value ? */
2513
2514 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2515 ctrl->timings[channel][slotrank].lanes[lane].falling =
2516 48;
2517 ctrl->timings[channel][slotrank].lanes[lane].rising =
2518 48;
2519 }
2520
2521 program_timings(ctrl, channel);
2522
2523 FOR_ALL_POPULATED_RANKS {
2524 wait_428c(channel);
2525
2526 /* DRAM command MRS
2527 * MR3 enable MPR
2528 * write MR3 MPR enable
2529 * in this mode only RD and RDA are allowed
2530 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002531 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2532 MCHBAR32(0x4230 + 0x400 * channel) =
2533 0xc01 | (ctrl->tMOD << 16);
2534 MCHBAR32(0x4200 + 0x400 * channel) =
2535 (slotrank << 24) | 0x360004;
2536 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002537
2538 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002539 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2540 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2541 MCHBAR32(0x4204 + 0x400 * channel) =
2542 (slotrank << 24) | 0;
2543 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002544
2545 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002546 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2547 MCHBAR32(0x4238 + 0x400 * channel) =
2548 0x1001 | ((ctrl->CAS + 8) << 16);
2549 MCHBAR32(0x4208 + 0x400 * channel) =
2550 (slotrank << 24) | 0x60000;
2551 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002552
2553 /* DRAM command MRS
2554 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002555 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2556 MCHBAR32(0x423c + 0x400 * channel) =
2557 0xc01 | (ctrl->tMOD << 16);
2558 MCHBAR32(0x420c + 0x400 * channel) =
2559 (slotrank << 24) | 0x360000;
2560 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002561
Felix Held9cf1dd22018-07-31 14:52:40 +02002562 // execute command queue
2563 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2564
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002565 wait_428c(channel);
2566 }
2567
2568 /* XXX: check any measured value ? */
2569
2570 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002571 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2572 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2573 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002574 }
2575
2576 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002577 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002578 }
2579
2580 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002581 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002582 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2583
2584 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2585 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002586 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002587 if (err)
2588 return err;
2589 }
2590
Felix Held2bb3cdf2018-07-28 00:23:59 +02002591 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002592 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2593
2594 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2595 err = discover_edges_real(ctrl, channel, slotrank,
2596 rising_edges[channel][slotrank]);
2597 if (err)
2598 return err;
2599 }
2600
Felix Held2bb3cdf2018-07-28 00:23:59 +02002601 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002602
2603 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2604 ctrl->timings[channel][slotrank].lanes[lane].falling =
2605 falling_edges[channel][slotrank][lane];
2606 ctrl->timings[channel][slotrank].lanes[lane].rising =
2607 rising_edges[channel][slotrank][lane];
2608 }
2609
2610 FOR_ALL_POPULATED_CHANNELS {
2611 program_timings(ctrl, channel);
2612 }
2613
2614 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002615 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002616 }
2617 return 0;
2618}
2619
2620static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2621 int slotrank, int *edges)
2622{
2623 int edge;
2624 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2625 int statistics[MAX_EDGE_TIMING + 1];
2626 const int reg3000b24[] = { 0, 0xc, 0x2c };
2627 int lane, i;
2628 int lower[NUM_LANES];
2629 int upper[NUM_LANES];
2630 int pat;
2631
2632 FOR_ALL_LANES {
2633 lower[lane] = 0;
2634 upper[lane] = MAX_EDGE_TIMING;
2635 }
2636
2637 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002638 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002639 printram("[%x] = 0x%08x\n",
2640 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2641 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2642 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002643 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002644 printram("using pattern %d\n", pat);
2645 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2646 FOR_ALL_LANES {
2647 ctrl->timings[channel][slotrank].lanes[lane].
2648 rising = edge;
2649 ctrl->timings[channel][slotrank].lanes[lane].
2650 falling = edge;
2651 }
2652 program_timings(ctrl, channel);
2653
2654 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002655 MCHBAR32(0x4340 + 0x400 * channel +
2656 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002657 MCHBAR32(0x400 * channel +
Felix Held2bb3cdf2018-07-28 00:23:59 +02002658 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002659 }
2660 wait_428c(channel);
2661
2662 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002663 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2664 MCHBAR32(0x4230 + 0x400 * channel) =
2665 0x4 | (ctrl->tRCD << 16) |
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002666 (MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002667 << 10);
2668 MCHBAR32(0x4200 + 0x400 * channel) =
2669 (slotrank << 24) | 0x60000;
2670 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002671
2672 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002673 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2674 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2675 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2676 MCHBAR32(0x4204 + 0x400 * channel) =
2677 slotrank << 24;
2678 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002679
2680 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002681 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2682 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002683 0x4005020 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002684 MCHBAR32(0x4208 + 0x400 * channel) =
2685 slotrank << 24;
2686 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002687
2688 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002689 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2690 MCHBAR32(0x423c + 0x400 * channel) =
2691 0xc01 | (ctrl->tRP << 16);
2692 MCHBAR32(0x420c + 0x400 * channel) =
2693 (slotrank << 24) | 0x60400;
2694 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002695
Felix Held9cf1dd22018-07-31 14:52:40 +02002696 // execute command queue
2697 MCHBAR32(0x4284 + 0x400 * channel) =
2698 RUN_QUEUE_4284(4);
2699
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002700 wait_428c(channel);
2701 FOR_ALL_LANES {
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002702 MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002703 0x400 * channel + lane * 4);
2704 }
2705
2706 raw_statistics[edge] =
2707 MCHBAR32(0x436c + 0x400 * channel);
2708 }
2709 FOR_ALL_LANES {
2710 struct run rn;
2711 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2712 statistics[edge] =
2713 ! !(raw_statistics[edge] & (1 << lane));
2714 rn = get_longest_zero_run(statistics,
2715 MAX_EDGE_TIMING + 1);
2716 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2717 channel, slotrank, i, rn.start, rn.middle,
2718 rn.end, rn.start + ctrl->edge_offset[i],
2719 rn.end - ctrl->edge_offset[i]);
2720 lower[lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002721 MAX(rn.start + ctrl->edge_offset[i], lower[lane]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002722 upper[lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002723 MIN(rn.end - ctrl->edge_offset[i], upper[lane]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002724 edges[lane] = (lower[lane] + upper[lane]) / 2;
2725 if (rn.all || (lower[lane] > upper[lane])) {
2726 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2727 channel, slotrank, lane);
2728 return MAKE_ERR;
2729 }
2730 }
2731 }
2732 }
2733
Felix Held2bb3cdf2018-07-28 00:23:59 +02002734 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002735 printram("CPA\n");
2736 return 0;
2737}
2738
2739int discover_edges_write(ramctr_timing *ctrl)
2740{
2741 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2742 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2743 int channel, slotrank, lane;
2744 int err;
2745
2746 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002747 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002748 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2749
2750 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2751 err = discover_edges_write_real(ctrl, channel, slotrank,
2752 falling_edges[channel][slotrank]);
2753 if (err)
2754 return err;
2755 }
2756
Felix Held2bb3cdf2018-07-28 00:23:59 +02002757 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002758 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2759
2760 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2761 err = discover_edges_write_real(ctrl, channel, slotrank,
2762 rising_edges[channel][slotrank]);
2763 if (err)
2764 return err;
2765 }
2766
Felix Held2bb3cdf2018-07-28 00:23:59 +02002767 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002768
2769 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2770 ctrl->timings[channel][slotrank].lanes[lane].falling =
2771 falling_edges[channel][slotrank][lane];
2772 ctrl->timings[channel][slotrank].lanes[lane].rising =
2773 rising_edges[channel][slotrank][lane];
2774 }
2775
2776 FOR_ALL_POPULATED_CHANNELS
2777 program_timings(ctrl, channel);
2778
2779 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002780 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002781 }
2782 return 0;
2783}
2784
2785static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2786{
2787 wait_428c(channel);
2788 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002789 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2790 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002791 (MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002792 << 10) | (ctrl->tRCD << 16) | 4;
2793 MCHBAR32(0x4200 + 0x400 * channel) =
2794 (slotrank << 24) | 0x60000;
2795 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002796
2797 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002798 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2799 MCHBAR32(0x4234 + 0x400 * channel) =
2800 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2801 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2802 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002803
2804 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002805 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2806 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002807 0x40011e0 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002808 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2809 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002810
2811 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002812 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2813 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2814 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2815 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002816
Felix Held9cf1dd22018-07-31 14:52:40 +02002817 // execute command queue
2818 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2819
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002820 wait_428c(channel);
2821}
2822
2823int discover_timC_write(ramctr_timing *ctrl)
2824{
2825 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2826 int i, pat;
2827
2828 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2829 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2830 int channel, slotrank, lane;
2831
2832 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2833 lower[channel][slotrank][lane] = 0;
2834 upper[channel][slotrank][lane] = MAX_TIMC;
2835 }
2836
Felix Held2bb3cdf2018-07-28 00:23:59 +02002837 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002838 printram("discover timC write:\n");
2839
2840 for (i = 0; i < 3; i++)
2841 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002842 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2843 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002844 udelay(2);
2845 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2846 FOR_ALL_POPULATED_RANKS {
2847 int timC;
2848 u32 raw_statistics[MAX_TIMC + 1];
2849 int statistics[MAX_TIMC + 1];
2850
2851 /* Make sure rn.start < rn.end */
2852 statistics[MAX_TIMC] = 1;
2853
2854 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002855 MCHBAR32(0x4288 + 0x400 * channel) =
2856 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002857 for (timC = 0; timC < MAX_TIMC; timC++) {
2858 FOR_ALL_LANES
2859 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2860 program_timings(ctrl, channel);
2861
2862 test_timC_write (ctrl, channel, slotrank);
2863
2864 raw_statistics[timC] =
2865 MCHBAR32(0x436c + 0x400 * channel);
2866 }
2867 FOR_ALL_LANES {
2868 struct run rn;
2869 for (timC = 0; timC < MAX_TIMC; timC++)
2870 statistics[timC] =
2871 !!(raw_statistics[timC] &
2872 (1 << lane));
2873
2874 rn = get_longest_zero_run(statistics,
2875 MAX_TIMC + 1);
2876 if (rn.all) {
2877 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2878 channel, slotrank, lane);
2879 return MAKE_ERR;
2880 }
2881 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2882 channel, slotrank, i, rn.start,
2883 rn.middle, rn.end,
2884 rn.start + ctrl->timC_offset[i],
2885 rn.end - ctrl->timC_offset[i]);
2886 lower[channel][slotrank][lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002887 MAX(rn.start + ctrl->timC_offset[i],
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002888 lower[channel][slotrank][lane]);
2889 upper[channel][slotrank][lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002890 MIN(rn.end - ctrl->timC_offset[i],
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002891 upper[channel][slotrank][lane]);
2892
2893 }
2894 }
2895 }
2896 }
2897
2898 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002899 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002900 udelay(2);
2901 }
2902
Felix Held2bb3cdf2018-07-28 00:23:59 +02002903 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002904
2905 printram("CPB\n");
2906
2907 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2908 printram("timC %d, %d, %d: %x\n", channel,
2909 slotrank, lane,
2910 (lower[channel][slotrank][lane] +
2911 upper[channel][slotrank][lane]) / 2);
2912 ctrl->timings[channel][slotrank].lanes[lane].timC =
2913 (lower[channel][slotrank][lane] +
2914 upper[channel][slotrank][lane]) / 2;
2915 }
2916 FOR_ALL_POPULATED_CHANNELS {
2917 program_timings(ctrl, channel);
2918 }
2919 return 0;
2920}
2921
2922void normalize_training(ramctr_timing * ctrl)
2923{
2924 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002925 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002926
2927 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2928 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002929 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002930 FOR_ALL_LANES mat =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002931 MAX(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002932 printram("normalize %d, %d, %d: mat %d\n",
2933 channel, slotrank, lane, mat);
2934
2935 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2936 printram("normalize %d, %d, %d: delta %d\n",
2937 channel, slotrank, lane, delta);
2938
2939 ctrl->timings[channel][slotrank].val_4024 += delta;
2940 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002941 }
2942
2943 FOR_ALL_POPULATED_CHANNELS {
2944 program_timings(ctrl, channel);
2945 }
2946}
2947
2948void write_controller_mr(ramctr_timing * ctrl)
2949{
2950 int channel, slotrank;
2951
2952 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002953 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2954 make_mr0(ctrl, slotrank);
2955 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2956 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002957 }
2958}
2959
2960int channel_test(ramctr_timing *ctrl)
2961{
2962 int channel, slotrank, lane;
2963
2964 slotrank = 0;
2965 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002966 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002967 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2968 channel);
2969 return MAKE_ERR;
2970 }
2971 FOR_ALL_POPULATED_CHANNELS {
2972 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2973
Felix Held2bb3cdf2018-07-28 00:23:59 +02002974 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002975 }
2976
2977 for (slotrank = 0; slotrank < 4; slotrank++)
2978 FOR_ALL_CHANNELS
2979 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2980 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002981 MCHBAR32(0x4f40 + 4 * lane) = 0;
2982 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002983 }
2984 wait_428c(channel);
Felix Held9cf1dd22018-07-31 14:52:40 +02002985
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002986 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002987 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2988 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2989 MCHBAR32(0x4200 + (channel << 10)) =
2990 0x00060000 | (slotrank << 24);
2991 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Felix Held9cf1dd22018-07-31 14:52:40 +02002992
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002993 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002994 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2995 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2996 MCHBAR32(0x4204 + (channel << 10)) =
2997 0x00000000 | (slotrank << 24);
2998 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002999
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003000 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02003001 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
3002 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
3003 MCHBAR32(0x4208 + (channel << 10)) =
3004 0x00000000 | (slotrank << 24);
3005 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02003006
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003007 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02003008 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
3009 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
3010 MCHBAR32(0x420c + (channel << 10)) =
3011 0x00060400 | (slotrank << 24);
3012 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
Felix Held9cf1dd22018-07-31 14:52:40 +02003013
3014 // execute command queue
3015 MCHBAR32(0x4284 + (channel << 10)) = RUN_QUEUE_4284(4);
3016
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003017 wait_428c(channel);
3018 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02003019 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003020 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
3021 channel, slotrank, lane);
3022 return MAKE_ERR;
3023 }
3024 }
3025 return 0;
3026}
3027
3028void set_scrambling_seed(ramctr_timing * ctrl)
3029{
3030 int channel;
3031
3032 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
3033 I don't think so. */
3034 static u32 seeds[NUM_CHANNELS][3] = {
3035 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
3036 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
3037 };
3038 FOR_ALL_POPULATED_CHANNELS {
3039 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02003040 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
3041 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
3042 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003043 }
3044}
3045
3046void set_4f8c(void)
3047{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003048 u32 cpu;
3049
Subrata Banik53b08c32018-12-10 14:11:35 +05303050 cpu = cpu_get_cpuid();
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003051 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3052 MCHBAR32(0x4f8c) = 0x141D1519;
3053 } else {
3054 MCHBAR32(0x4f8c) = 0x551D1519;
3055 }
3056}
3057
3058void prepare_training(ramctr_timing * ctrl)
3059{
3060 int channel;
3061
3062 FOR_ALL_POPULATED_CHANNELS {
3063 // Always drive command bus
Felix Held9fe248f2018-07-31 20:59:45 +02003064 MCHBAR32_OR(0x4004 + 0x400 * channel, 0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003065 }
3066
3067 udelay(1);
3068
3069 FOR_ALL_POPULATED_CHANNELS {
3070 wait_428c(channel);
3071 }
3072}
3073
3074void set_4008c(ramctr_timing * ctrl)
3075{
3076 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003077
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003078 FOR_ALL_POPULATED_CHANNELS {
3079 u32 b20, b4_8_12;
3080 int min_320c = 10000;
3081 int max_320c = -10000;
3082
3083 FOR_ALL_POPULATED_RANKS {
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01003084 max_320c = MAX(ctrl->timings[channel][slotrank].val_320c, max_320c);
3085 min_320c = MIN(ctrl->timings[channel][slotrank].val_320c, min_320c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003086 }
3087
3088 if (max_320c - min_320c > 51)
3089 b20 = 0;
3090 else
3091 b20 = ctrl->ref_card_offset[channel];
3092
3093 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3094 b4_8_12 = 0x3330;
3095 else
3096 b4_8_12 = 0x2220;
3097
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003098 dram_odt_stretch(ctrl, channel);
3099
Felix Held2bb3cdf2018-07-28 00:23:59 +02003100 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003101 0x0a000000 | (b20 << 20) |
3102 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003103 }
3104}
3105
3106void set_42a0(ramctr_timing * ctrl)
3107{
3108 int channel;
3109 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003110 MCHBAR32(0x42a0 + 0x400 * channel) =
3111 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003112 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003113 }
3114}
3115
3116static int encode_5d10(int ns)
3117{
3118 return (ns + 499) / 500;
3119}
3120
3121/* FIXME: values in this function should be hardware revision-dependent. */
3122void final_registers(ramctr_timing * ctrl)
3123{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003124 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3125
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003126 int channel;
3127 int t1_cycles = 0, t1_ns = 0, t2_ns;
3128 int t3_ns;
3129 u32 r32;
3130
Felix Held2bb3cdf2018-07-28 00:23:59 +02003131 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003132
Felix Heldf9b826a2018-07-30 17:56:52 +02003133 FOR_ALL_CHANNELS
3134 MCHBAR32_AND_OR(0x400c + 0x400 * channel, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003135
Patrick Rudolph74203de2017-11-20 11:57:01 +01003136 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003137 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3138 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3139 else
3140 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3141 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3142
Felix Heldf9b826a2018-07-30 17:56:52 +02003143 FOR_ALL_CHANNELS
3144 MCHBAR32(0x4380 + 0x400 * channel) = 0x00000aaa;
3145
Felix Held2bb3cdf2018-07-28 00:23:59 +02003146 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3147 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003148
3149 FOR_ALL_CHANNELS {
3150 switch (ctrl->rankmap[channel]) {
3151 /* Unpopulated channel. */
3152 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003153 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003154 break;
3155 /* Only single-ranked dimms. */
3156 case 1:
3157 case 4:
3158 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003159 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003160 break;
3161 /* Dual-ranked dimms present. */
3162 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003163 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003164 break;
3165 }
3166 }
3167
Felix Held2bb3cdf2018-07-28 00:23:59 +02003168 MCHBAR32(0x5880) = 0xca9171e5;
Felix Held2463aa92018-07-29 21:37:55 +02003169 MCHBAR32_AND_OR(0x5888, ~0xffffff, 0xe4d5d0);
3170 MCHBAR32_AND(0x58a8, ~0x1f);
Felix Heldf9b826a2018-07-30 17:56:52 +02003171
3172 FOR_ALL_CHANNELS
3173 MCHBAR32_AND_OR(0x4294 + 0x400 * channel, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003174
Felix Held9fe248f2018-07-31 20:59:45 +02003175 MCHBAR32_OR(0x5030, 1);
3176 MCHBAR32_OR(0x5030, 0x80);
Felix Held2463aa92018-07-29 21:37:55 +02003177 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003178
3179 /* Find a populated channel. */
3180 FOR_ALL_POPULATED_CHANNELS
3181 break;
3182
Felix Held2bb3cdf2018-07-28 00:23:59 +02003183 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3184 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003185 if (r32 & 0x20000)
3186 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003187 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003188 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3189 if (!(r32 & 0x20000))
3190 t1_ns += 500;
3191
Felix Held2bb3cdf2018-07-28 00:23:59 +02003192 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3193 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003194 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003195 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3196 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003197 }
3198 else
3199 {
3200 t3_ns = 500;
3201 }
3202 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3203 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003204 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3205 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003206 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003207 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003208}
3209
3210void restore_timings(ramctr_timing * ctrl)
3211{
3212 int channel, slotrank, lane;
3213
3214 FOR_ALL_POPULATED_CHANNELS
3215 MCHBAR32(0x4004 + 0x400 * channel) =
3216 ctrl->tRRD
3217 | (ctrl->tRTP << 4)
3218 | (ctrl->tCKE << 8)
3219 | (ctrl->tWTR << 12)
3220 | (ctrl->tFAW << 16)
3221 | (ctrl->tWR << 24)
3222 | (ctrl->cmd_stretch[channel] << 30);
3223
3224 udelay(1);
3225
3226 FOR_ALL_POPULATED_CHANNELS {
3227 wait_428c(channel);
3228 }
3229
3230 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003231 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003232 }
3233
3234 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003235 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003236
3237 FOR_ALL_POPULATED_CHANNELS {
3238 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003239 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003240 }
3241
3242 printram("CPE\n");
3243
Felix Held2bb3cdf2018-07-28 00:23:59 +02003244 MCHBAR32(0x3400) = 0;
3245 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003246
3247 printram("CP5b\n");
3248
3249 FOR_ALL_POPULATED_CHANNELS {
3250 program_timings(ctrl, channel);
3251 }
3252
3253 u32 reg, addr;
3254
3255 while (!(MCHBAR32(0x5084) & 0x10000));
3256 do {
3257 reg = MCHBAR32(0x428c);
3258 } while ((reg & 0x14) == 0);
3259
3260 // Set state of memory controller
3261 MCHBAR32(0x5030) = 0x116;
3262 MCHBAR32(0x4ea0) = 0;
3263
3264 // Wait 500us
3265 udelay(500);
3266
3267 FOR_ALL_CHANNELS {
3268 // Set valid rank CKE
3269 reg = 0;
3270 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3271 addr = 0x400 * channel + 0x42a0;
3272 MCHBAR32(addr) = reg;
3273
3274 // Wait 10ns for ranks to settle
3275 //udelay(0.01);
3276
3277 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3278 MCHBAR32(addr) = reg;
3279
3280 // Write reset using a NOP
3281 write_reset(ctrl);
3282 }
3283
3284 /* mrs commands. */
3285 dram_mrscommands(ctrl);
3286
3287 printram("CP5c\n");
3288
Felix Held2bb3cdf2018-07-28 00:23:59 +02003289 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003290
3291 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003292 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003293 udelay(2);
3294 }
3295
Felix Held2bb3cdf2018-07-28 00:23:59 +02003296 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003297}