blob: 4ce059a322de8b0c01e1fb77f4dba53379a8eebb [file] [log] [blame]
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
5 * Copyright (C) 2014 Vladimir Serbinenko <phcoder@gmail.com>
6 * Copyright (C) 2016 Patrick Rudolph <siro@das-labor.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <console/console.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010019#include <string.h>
Subrata Banik53b08c32018-12-10 14:11:35 +053020#include <arch/cpu.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010021#include <arch/io.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010022#include <northbridge/intel/sandybridge/chip.h>
23#include <device/pci_def.h>
24#include <delay.h>
25#include <arch/cpu.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010026#include "raminit_native.h"
27#include "raminit_common.h"
28#include "sandybridge.h"
29
30/* FIXME: no ECC support. */
31/* FIXME: no support for 3-channel chipsets. */
32
33/*
34 * Register description:
35 * Intel provides a command queue of depth four.
36 * Every command is configured by using multiple registers.
37 * On executing the command queue you have to provide the depth used.
38 *
39 * Known registers:
40 * Channel X = [0, 1]
41 * Command queue index Y = [0, 1, 2, 3]
42 *
43 * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register
44 * Controls the DRAM command signals
45 * Bit 0: !RAS
46 * Bit 1: !CAS
47 * Bit 2: !WE
48 *
49 * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register
50 * Controls the address, bank address and slotrank signals
51 * Bit 0-15 : Address
52 * Bit 20-22: Bank Address
53 * Bit 24-25: slotrank
54 *
55 * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register
56 * Controls the idle time after issuing this DRAM command
57 * Bit 16-32: number of clock-cylces to idle
58 *
59 * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue
60 * Starts to execute all queued commands
61 * Bit 0 : start DRAM command execution
Felix Held9cf1dd22018-07-31 14:52:40 +020062 * Bit 18-19 : number of queued commands - 1
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010063 */
64
Felix Held9cf1dd22018-07-31 14:52:40 +020065#define RUN_QUEUE_4284(x) ((((x) - 1) << 18) | 1) // 0 <= x < 4
66
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010067static void sfence(void)
68{
69 asm volatile ("sfence");
70}
71
72static void toggle_io_reset(void) {
73 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020074 u32 r32 = MCHBAR32(0x5030);
75 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010076 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020077 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010078 udelay(1);
79}
80
81static u32 get_XOVER_CLK(u8 rankmap)
82{
83 return rankmap << 24;
84}
85
86static u32 get_XOVER_CMD(u8 rankmap)
87{
88 u32 reg;
89
90 // enable xover cmd
91 reg = 0x4000;
92
93 // enable xover ctl
94 if (rankmap & 0x3)
95 reg |= 0x20000;
96
97 if (rankmap & 0xc)
98 reg |= 0x4000000;
99
100 return reg;
101}
102
103/* CAS write latency. To be programmed in MR2.
104 * See DDR3 SPEC for MR2 documentation. */
105u8 get_CWL(u32 tCK)
106{
107 /* Get CWL based on tCK using the following rule: */
108 switch (tCK) {
109 case TCK_1333MHZ:
110 return 12;
111 case TCK_1200MHZ:
112 case TCK_1100MHZ:
113 return 11;
114 case TCK_1066MHZ:
115 case TCK_1000MHZ:
116 return 10;
117 case TCK_933MHZ:
118 case TCK_900MHZ:
119 return 9;
120 case TCK_800MHZ:
121 case TCK_700MHZ:
122 return 8;
123 case TCK_666MHZ:
124 return 7;
125 case TCK_533MHZ:
126 return 6;
127 default:
128 return 5;
129 }
130}
131
132void dram_find_common_params(ramctr_timing *ctrl)
133{
134 size_t valid_dimms;
135 int channel, slot;
136 dimm_info *dimms = &ctrl->info;
137
138 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
139 valid_dimms = 0;
140 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
141 const dimm_attr *dimm = &dimms->dimm[channel][slot];
142 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
143 continue;
144 valid_dimms++;
145
146 /* Find all possible CAS combinations */
147 ctrl->cas_supported &= dimm->cas_supported;
148
149 /* Find the smallest common latencies supported by all DIMMs */
150 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
151 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
152 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
153 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
154 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
155 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
156 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
157 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
158 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
159 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
160 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300161 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
162 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100163 }
164
165 if (!ctrl->cas_supported)
166 die("Unsupported DIMM combination. "
167 "DIMMS do not support common CAS latency");
168 if (!valid_dimms)
169 die("No valid DIMMs found");
170}
171
172void dram_xover(ramctr_timing * ctrl)
173{
174 u32 reg;
175 int channel;
176
177 FOR_ALL_CHANNELS {
178 // enable xover clk
179 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
180 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
181 reg);
182 MCHBAR32(channel * 0x100 + 0xc14) = reg;
183
184 // enable xover ctl & xover cmd
185 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
186 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
187 reg);
188 MCHBAR32(0x100 * channel + 0x320c) = reg;
189 }
190}
191
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100192static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100193{
Iru Cai89af71c2018-08-16 16:46:27 +0800194 u32 addr, cpu, stretch;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100195
196 stretch = ctrl->ref_card_offset[channel];
197 /* ODT stretch: Delay ODT signal by stretch value.
198 * Useful for multi DIMM setups on the same channel. */
Subrata Banik53b08c32018-12-10 14:11:35 +0530199 cpu = cpu_get_cpuid();
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100200 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
201 if (stretch == 2)
202 stretch = 3;
Iru Cai89af71c2018-08-16 16:46:27 +0800203 addr = 0x401c + 0x400 * channel;
204 MCHBAR32_AND_OR(addr, 0xffffc3ff,
Felix Held9fe248f2018-07-31 20:59:45 +0200205 (stretch << 12) | (stretch << 10));
Iru Cai89af71c2018-08-16 16:46:27 +0800206 printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr,
207 MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100208 } else {
209 // OTHP
Iru Cai89af71c2018-08-16 16:46:27 +0800210 addr = 0x400c + 0x400 * channel;
211 MCHBAR32_AND_OR(addr, 0xfff0ffff,
Felix Held9fe248f2018-07-31 20:59:45 +0200212 (stretch << 16) | (stretch << 18));
Iru Cai89af71c2018-08-16 16:46:27 +0800213 printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100214 }
215}
216
217void dram_timing_regs(ramctr_timing *ctrl)
218{
219 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100220 int channel;
221
222 FOR_ALL_CHANNELS {
223 // DBP
224 reg = 0;
225 reg |= ctrl->tRCD;
226 reg |= (ctrl->tRP << 4);
227 reg |= (ctrl->CAS << 8);
228 reg |= (ctrl->CWL << 12);
229 reg |= (ctrl->tRAS << 16);
230 printram("DBP [%x] = %x\n", 0x400 * channel + 0x4000, reg);
231 MCHBAR32(0x400 * channel + 0x4000) = reg;
232
233 // RAP
234 reg = 0;
235 reg |= ctrl->tRRD;
236 reg |= (ctrl->tRTP << 4);
237 reg |= (ctrl->tCKE << 8);
238 reg |= (ctrl->tWTR << 12);
239 reg |= (ctrl->tFAW << 16);
240 reg |= (ctrl->tWR << 24);
241 reg |= (3 << 30);
242 printram("RAP [%x] = %x\n", 0x400 * channel + 0x4004, reg);
243 MCHBAR32(0x400 * channel + 0x4004) = reg;
244
245 // OTHP
246 addr = 0x400 * channel + 0x400c;
247 reg = 0;
248 reg |= ctrl->tXPDLL;
249 reg |= (ctrl->tXP << 5);
250 reg |= (ctrl->tAONPD << 8);
251 reg |= 0xa0000;
252 printram("OTHP [%x] = %x\n", addr, reg);
253 MCHBAR32(addr) = reg;
254
255 MCHBAR32(0x400 * channel + 0x4014) = 0;
256
Felix Held9fe248f2018-07-31 20:59:45 +0200257 MCHBAR32_OR(addr, 0x00020000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100258
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100259 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100260
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100261 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200262 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100263 * The tREFIx9 field should be programmed to minimum of
264 * 8.9*tREFI (to allow for possible delays from ZQ or
265 * isoc) and tRASmax (70us) divided by 1024.
266 */
267 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
268
269 reg = ((ctrl->tREFI & 0xffff) << 0) |
270 ((ctrl->tRFC & 0x1ff) << 16) |
271 (((val32 / 1024) & 0x7f) << 25);
272 printram("REFI [%x] = %x\n", 0x400 * channel + 0x4298, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100273 MCHBAR32(0x400 * channel + 0x4298) = reg;
274
Felix Held9fe248f2018-07-31 20:59:45 +0200275 MCHBAR32_OR(0x400 * channel + 0x4294, 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100276
277 // SRFTP
278 reg = 0;
279 val32 = tDLLK;
280 reg = (reg & ~0xfff) | val32;
281 val32 = ctrl->tXSOffset;
282 reg = (reg & ~0xf000) | (val32 << 12);
283 val32 = tDLLK - ctrl->tXSOffset;
284 reg = (reg & ~0x3ff0000) | (val32 << 16);
285 val32 = ctrl->tMOD - 8;
286 reg = (reg & ~0xf0000000) | (val32 << 28);
287 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
288 reg);
289 MCHBAR32(0x400 * channel + 0x42a4) = reg;
290 }
291}
292
293void dram_dimm_mapping(ramctr_timing *ctrl)
294{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100295 int channel;
296 dimm_info *info = &ctrl->info;
297
298 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200299 dimm_attr *dimmA, *dimmB;
300 u32 reg = 0;
301
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100302 if (info->dimm[channel][0].size_mb >=
303 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100304 dimmA = &info->dimm[channel][0];
305 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200306 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100307 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100308 dimmA = &info->dimm[channel][1];
309 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200310 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100311 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100312
Nico Huberac4f2162017-10-01 18:14:43 +0200313 if (dimmA && (dimmA->ranks > 0)) {
314 reg |= dimmA->size_mb / 256;
315 reg |= (dimmA->ranks - 1) << 17;
316 reg |= (dimmA->width / 8 - 1) << 19;
317 }
318
319 if (dimmB && (dimmB->ranks > 0)) {
320 reg |= (dimmB->size_mb / 256) << 8;
321 reg |= (dimmB->ranks - 1) << 18;
322 reg |= (dimmB->width / 8 - 1) << 20;
323 }
324
325 reg |= 1 << 21; /* rank interleave */
326 reg |= 1 << 22; /* enhanced interleave */
327
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100328 if ((dimmA && (dimmA->ranks > 0))
329 || (dimmB && (dimmB->ranks > 0))) {
330 ctrl->mad_dimm[channel] = reg;
331 } else {
332 ctrl->mad_dimm[channel] = 0;
333 }
334 }
335}
336
337void dram_dimm_set_mapping(ramctr_timing * ctrl)
338{
339 int channel;
340 FOR_ALL_CHANNELS {
341 MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
342 }
343}
344
345void dram_zones(ramctr_timing * ctrl, int training)
346{
347 u32 reg, ch0size, ch1size;
348 u8 val;
349 reg = 0;
350 val = 0;
351 if (training) {
352 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
353 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
354 } else {
355 ch0size = ctrl->channel_size_mb[0];
356 ch1size = ctrl->channel_size_mb[1];
357 }
358
359 if (ch0size >= ch1size) {
360 reg = MCHBAR32(0x5014);
361 val = ch1size / 256;
362 reg = (reg & ~0xff000000) | val << 24;
363 reg = (reg & ~0xff0000) | (2 * val) << 16;
364 MCHBAR32(0x5014) = reg;
365 MCHBAR32(0x5000) = 0x24;
366 } else {
367 reg = MCHBAR32(0x5014);
368 val = ch0size / 256;
369 reg = (reg & ~0xff000000) | val << 24;
370 reg = (reg & ~0xff0000) | (2 * val) << 16;
371 MCHBAR32(0x5014) = reg;
372 MCHBAR32(0x5000) = 0x21;
373 }
374}
375
376#define HOST_BRIDGE PCI_DEVFN(0, 0)
377#define DEFAULT_TCK TCK_800MHZ
378
379unsigned int get_mem_min_tck(void)
380{
381 u32 reg32;
382 u8 rev;
383 const struct device *dev;
384 const struct northbridge_intel_sandybridge_config *cfg = NULL;
385
386 dev = dev_find_slot(0, HOST_BRIDGE);
387 if (dev)
388 cfg = dev->chip_info;
389
390 /* If this is zero, it just means devicetree.cb didn't set it */
391 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Patrick Rudolphb794a692017-08-08 13:13:51 +0200392 if (IS_ENABLED(CONFIG_NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
393 return TCK_1333MHZ;
394
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100395 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
396
397 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
398 /* read Capabilities A Register DMFC bits */
399 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
400 reg32 &= 0x7;
401
402 switch (reg32) {
403 case 7: return TCK_533MHZ;
404 case 6: return TCK_666MHZ;
405 case 5: return TCK_800MHZ;
406 /* reserved: */
407 default:
408 break;
409 }
410 } else {
411 /* read Capabilities B Register DMFC bits */
412 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
413 reg32 = (reg32 >> 4) & 0x7;
414
415 switch (reg32) {
416 case 7: return TCK_533MHZ;
417 case 6: return TCK_666MHZ;
418 case 5: return TCK_800MHZ;
419 case 4: return TCK_933MHZ;
420 case 3: return TCK_1066MHZ;
421 case 2: return TCK_1200MHZ;
422 case 1: return TCK_1333MHZ;
423 /* reserved: */
424 default:
425 break;
426 }
427 }
428 return DEFAULT_TCK;
429 } else {
430 if (cfg->max_mem_clock_mhz >= 1066)
431 return TCK_1066MHZ;
432 else if (cfg->max_mem_clock_mhz >= 933)
433 return TCK_933MHZ;
434 else if (cfg->max_mem_clock_mhz >= 800)
435 return TCK_800MHZ;
436 else if (cfg->max_mem_clock_mhz >= 666)
437 return TCK_666MHZ;
438 else if (cfg->max_mem_clock_mhz >= 533)
439 return TCK_533MHZ;
440 else
441 return TCK_400MHZ;
442 }
443}
444
445#define DEFAULT_PCI_MMIO_SIZE 2048
446
447static unsigned int get_mmio_size(void)
448{
449 const struct device *dev;
450 const struct northbridge_intel_sandybridge_config *cfg = NULL;
451
452 dev = dev_find_slot(0, HOST_BRIDGE);
453 if (dev)
454 cfg = dev->chip_info;
455
456 /* If this is zero, it just means devicetree.cb didn't set it */
457 if (!cfg || cfg->pci_mmio_size == 0)
458 return DEFAULT_PCI_MMIO_SIZE;
459 else
460 return cfg->pci_mmio_size;
461}
462
463void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
464{
465 u32 reg, val, reclaim;
466 u32 tom, gfxstolen, gttsize;
467 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
468 tsegbase, mestolenbase;
469 size_t tsegbasedelta, remapbase, remaplimit;
470 uint16_t ggc;
471
472 mmiosize = get_mmio_size();
473
474 ggc = pci_read_config16(NORTHBRIDGE, GGC);
475 if (!(ggc & 2)) {
476 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
477 gttsize = ((ggc >> 8) & 0x3);
478 } else {
479 gfxstolen = 0;
480 gttsize = 0;
481 }
482
483 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
484
485 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
486
487 mestolenbase = tom - me_uma_size;
488
489 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
490 tom - me_uma_size);
491 gfxstolenbase = toludbase - gfxstolen;
492 gttbase = gfxstolenbase - gttsize;
493
494 tsegbase = gttbase - tsegsize;
495
496 // Round tsegbase down to nearest address aligned to tsegsize
497 tsegbasedelta = tsegbase & (tsegsize - 1);
498 tsegbase &= ~(tsegsize - 1);
499
500 gttbase -= tsegbasedelta;
501 gfxstolenbase -= tsegbasedelta;
502 toludbase -= tsegbasedelta;
503
504 // Test if it is possible to reclaim a hole in the RAM addressing
505 if (tom - me_uma_size > toludbase) {
506 // Reclaim is possible
507 reclaim = 1;
508 remapbase = MAX(4096, tom - me_uma_size);
509 remaplimit =
510 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
511 touudbase = remaplimit + 1;
512 } else {
513 // Reclaim not possible
514 reclaim = 0;
515 touudbase = tom - me_uma_size;
516 }
517
518 // Update memory map in pci-e configuration space
519 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
520
521 // TOM (top of memory)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300522 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100523 val = tom & 0xfff;
524 reg = (reg & ~0xfff00000) | (val << 20);
525 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300526 pci_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100527
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300528 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100529 val = tom & 0xfffff000;
530 reg = (reg & ~0x000fffff) | (val >> 12);
531 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300532 pci_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100533
534 // TOLUD (top of low used dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300535 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xbc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100536 val = toludbase & 0xfff;
537 reg = (reg & ~0xfff00000) | (val << 20);
538 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xbc, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300539 pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100540
541 // TOUUD LSB (top of upper usable dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300542 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100543 val = touudbase & 0xfff;
544 reg = (reg & ~0xfff00000) | (val << 20);
545 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300546 pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100547
548 // TOUUD MSB
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300549 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xac);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100550 val = touudbase & 0xfffff000;
551 reg = (reg & ~0x000fffff) | (val >> 12);
552 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xac, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300553 pci_write_config32(PCI_DEV(0, 0, 0), 0xac, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100554
555 if (reclaim) {
556 // REMAP BASE
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300557 pci_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20);
558 pci_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100559
560 // REMAP LIMIT
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300561 pci_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20);
562 pci_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100563 }
564 // TSEG
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300565 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100566 val = tsegbase & 0xfff;
567 reg = (reg & ~0xfff00000) | (val << 20);
568 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300569 pci_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100570
571 // GFX stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300572 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100573 val = gfxstolenbase & 0xfff;
574 reg = (reg & ~0xfff00000) | (val << 20);
575 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300576 pci_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100577
578 // GTT stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300579 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100580 val = gttbase & 0xfff;
581 reg = (reg & ~0xfff00000) | (val << 20);
582 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300583 pci_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100584
585 if (me_uma_size) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300586 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x7c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100587 val = (0x80000 - me_uma_size) & 0xfffff000;
588 reg = (reg & ~0x000fffff) | (val >> 12);
589 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x7c, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300590 pci_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100591
592 // ME base
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300593 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x70);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100594 val = mestolenbase & 0xfff;
595 reg = (reg & ~0xfff00000) | (val << 20);
596 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x70, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300597 pci_write_config32(PCI_DEV(0, 0, 0), 0x70, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100598
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300599 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x74);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100600 val = mestolenbase & 0xfffff000;
601 reg = (reg & ~0x000fffff) | (val >> 12);
602 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x74, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300603 pci_write_config32(PCI_DEV(0, 0, 0), 0x74, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100604
605 // ME mask
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300606 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x78);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100607 val = (0x80000 - me_uma_size) & 0xfff;
608 reg = (reg & ~0xfff00000) | (val << 20);
609 reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem
610
611 reg = (reg & ~0x800) | (1 << 11); // set ME memory enable
612 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x78, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300613 pci_write_config32(PCI_DEV(0, 0, 0), 0x78, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100614 }
615}
616
617static void wait_428c(int channel)
618{
619 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200620 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100621 return;
622 }
623}
624
625static void write_reset(ramctr_timing * ctrl)
626{
627 int channel, slotrank;
628
629 /* choose a populated channel. */
630 channel = (ctrl->rankmap[0]) ? 0 : 1;
631
632 wait_428c(channel);
633
634 /* choose a populated rank. */
635 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
636
637 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200638 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
639 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200640 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200641 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100642
Felix Held9cf1dd22018-07-31 14:52:40 +0200643 // execute command queue - why is bit 22 set here?!
644 MCHBAR32(0x4284 + 0x400 * channel) = (1 << 22) | RUN_QUEUE_4284(1);
645
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100646 wait_428c(channel);
647}
648
649void dram_jedecreset(ramctr_timing * ctrl)
650{
Felix Held9fe248f2018-07-31 20:59:45 +0200651 u32 reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100652 int channel;
653
654 while (!(MCHBAR32(0x5084) & 0x10000));
655 do {
656 reg = MCHBAR32(0x428c);
657 } while ((reg & 0x14) == 0);
658
659 // Set state of memory controller
660 reg = 0x112;
661 MCHBAR32(0x5030) = reg;
662 MCHBAR32(0x4ea0) = 0;
663 reg |= 2; //ddr reset
664 MCHBAR32(0x5030) = reg;
665
666 // Assert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200667 MCHBAR32_AND(0x5030, ~0x2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100668
669 // Wait 200us
670 udelay(200);
671
672 // Deassert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200673 MCHBAR32_OR(0x5030, 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100674
675 // Wait 500us
676 udelay(500);
677
678 // Enable DCLK
Felix Held9fe248f2018-07-31 20:59:45 +0200679 MCHBAR32_OR(0x5030, 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100680
681 // XXX Wait 20ns
682 udelay(1);
683
684 FOR_ALL_CHANNELS {
685 // Set valid rank CKE
Felix Held9fe248f2018-07-31 20:59:45 +0200686 reg = ctrl->rankmap[channel];
687 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100688
689 // Wait 10ns for ranks to settle
690 //udelay(0.01);
691
692 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
Felix Held9fe248f2018-07-31 20:59:45 +0200693 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100694
695 // Write reset using a NOP
696 write_reset(ctrl);
697 }
698}
699
700static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
701{
702 /* Get ODT based on rankmap: */
703 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
704 + ((ctrl->rankmap[channel] >> 2) & 1);
705
706 if (dimms_per_ch == 1) {
707 return (const odtmap){60, 60};
708 } else {
709 return (const odtmap){120, 30};
710 }
711}
712
713static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
714 int reg, u32 val)
715{
716 wait_428c(channel);
717
718 if (ctrl->rank_mirror[channel][slotrank]) {
719 /* DDR3 Rank1 Address mirror
720 * swap the following pins:
721 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
722 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
723 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
724 | ((val & 0xa8) << 1);
725 }
726
727 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200728 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
729 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
730 MCHBAR32(0x4200 + 0x400 * channel) =
731 (slotrank << 24) | (reg << 20) | val | 0x60000;
732 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100733
734 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200735 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
736 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
737 MCHBAR32(0x4204 + 0x400 * channel) =
738 (slotrank << 24) | (reg << 20) | val | 0x60000;
739 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100740
741 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200742 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
743 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
744 MCHBAR32(0x4208 + 0x400 * channel) =
745 (slotrank << 24) | (reg << 20) | val | 0x60000;
746 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200747
748 // execute command queue
749 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100750}
751
752static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
753{
754 u16 mr0reg, mch_cas, mch_wr;
755 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 +0100756 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100757
758 /* DLL Reset - self clearing - set after CLK frequency has been changed */
759 mr0reg = 0x100;
760
761 // Convert CAS to MCH register friendly
762 if (ctrl->CAS < 12) {
763 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
764 } else {
765 mch_cas = (u16) (ctrl->CAS - 12);
766 mch_cas = ((mch_cas << 1) | 0x1);
767 }
768
769 // Convert tWR to MCH register friendly
770 mch_wr = mch_wr_t[ctrl->tWR - 5];
771
772 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
773 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
774 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
775
776 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100777 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100778 return mr0reg;
779}
780
781static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
782{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200783 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100784}
785
786static u32 encode_odt(u32 odt)
787{
788 switch (odt) {
789 case 30:
790 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
791 case 60:
792 return (1 << 2); // RZQ/4
793 case 120:
794 return (1 << 6); // RZQ/2
795 default:
796 case 0:
797 return 0;
798 }
799}
800
801static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
802{
803 odtmap odt;
804 u32 mr1reg;
805
806 odt = get_ODT(ctrl, rank, channel);
807 mr1reg = 0x2;
808
809 mr1reg |= encode_odt(odt.rttnom);
810
811 return mr1reg;
812}
813
814static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
815{
816 u16 mr1reg;
817
818 mr1reg = make_mr1(ctrl, rank, channel);
819
820 write_mrreg(ctrl, channel, rank, 1, mr1reg);
821}
822
823static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
824{
825 u16 pasr, cwl, mr2reg;
826 odtmap odt;
827 int srt;
828
829 pasr = 0;
830 cwl = ctrl->CWL - 5;
831 odt = get_ODT(ctrl, rank, channel);
832
833 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
834
835 mr2reg = 0;
836 mr2reg = (mr2reg & ~0x7) | pasr;
837 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
838 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
839 mr2reg = (mr2reg & ~0x80) | (srt << 7);
840 mr2reg |= (odt.rttwr / 60) << 9;
841
842 write_mrreg(ctrl, channel, rank, 2, mr2reg);
843}
844
845static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
846{
847 write_mrreg(ctrl, channel, rank, 3, 0);
848}
849
850void dram_mrscommands(ramctr_timing * ctrl)
851{
852 u8 slotrank;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100853 int channel;
854
855 FOR_ALL_POPULATED_CHANNELS {
856 FOR_ALL_POPULATED_RANKS {
857 // MR2
858 dram_mr2(ctrl, slotrank, channel);
859
860 // MR3
861 dram_mr3(ctrl, slotrank, channel);
862
863 // MR1
864 dram_mr1(ctrl, slotrank, channel);
865
866 // MR0
867 dram_mr0(ctrl, slotrank, channel);
868 }
869 }
870
871 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200872 MCHBAR32(0x4e20) = 0x7;
873 MCHBAR32(0x4e30) = 0xf1001;
874 MCHBAR32(0x4e00) = 0x60002;
875 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100876
877 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200878 MCHBAR32(0x4e24) = 0x1f003;
879 MCHBAR32(0x4e34) = 0x1901001;
880 MCHBAR32(0x4e04) = 0x60400;
881 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100882
Felix Held9cf1dd22018-07-31 14:52:40 +0200883 // execute command queue on all channels? Why isn't bit 0 set here?
Felix Held2bb3cdf2018-07-28 00:23:59 +0200884 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100885
886 // Drain
887 FOR_ALL_CHANNELS {
888 // Wait for ref drained
889 wait_428c(channel);
890 }
891
892 // Refresh enable
Felix Held9fe248f2018-07-31 20:59:45 +0200893 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100894
895 FOR_ALL_POPULATED_CHANNELS {
Felix Held9fe248f2018-07-31 20:59:45 +0200896 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100897
898 wait_428c(channel);
899
900 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
901
902 // Drain
903 wait_428c(channel);
904
905 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200906 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
907 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
908 MCHBAR32(0x4200 + 0x400 * channel) =
909 (slotrank << 24) | 0x60000;
910 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200911
912 // execute command queue
913 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100914
915 // Drain
916 wait_428c(channel);
917 }
918}
919
920static const u32 lane_registers[] = {
921 0x0000, 0x0200, 0x0400, 0x0600,
922 0x1000, 0x1200, 0x1400, 0x1600,
923 0x0800
924};
925
926void program_timings(ramctr_timing * ctrl, int channel)
927{
928 u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028;
929 int lane;
930 int slotrank, slot;
931 int full_shift = 0;
932 u16 slot320c[NUM_SLOTS];
933
934 FOR_ALL_POPULATED_RANKS {
935 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
936 full_shift = -ctrl->timings[channel][slotrank].val_320c;
937 }
938
939 for (slot = 0; slot < NUM_SLOTS; slot++)
940 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
941 case 0:
942 default:
943 slot320c[slot] = 0x7f;
944 break;
945 case 1:
946 slot320c[slot] =
947 ctrl->timings[channel][2 * slot + 0].val_320c +
948 full_shift;
949 break;
950 case 2:
951 slot320c[slot] =
952 ctrl->timings[channel][2 * slot + 1].val_320c +
953 full_shift;
954 break;
955 case 3:
956 slot320c[slot] =
957 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200958 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100959 full_shift;
960 break;
961 }
962
963 /* enable CMD XOVER */
964 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
965 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
966 reg32 |= (slot320c[1] & 0x7f) << 18;
967 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
968
969 MCHBAR32(0x320c + 0x100 * channel) = reg32;
970
971 /* enable CLK XOVER */
972 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
973 reg_c18 = 0;
974
975 FOR_ALL_POPULATED_RANKS {
976 int shift =
977 ctrl->timings[channel][slotrank].val_320c + full_shift;
978 int offset_val_c14;
979 if (shift < 0)
980 shift = 0;
981 offset_val_c14 = ctrl->reg_c14_offset + shift;
982 /* set CLK phase shift */
983 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
984 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
985 }
986
987 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
988 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
989
990 reg_4028 = MCHBAR32(0x4028 + 0x400 * channel);
991 reg_4028 &= 0xffff0000;
992
993 reg_4024 = 0;
994
995 FOR_ALL_POPULATED_RANKS {
996 int post_timA_min_high = 7, post_timA_max_high = 0;
997 int pre_timA_min_high = 7, pre_timA_max_high = 0;
998 int shift_402x = 0;
999 int shift =
1000 ctrl->timings[channel][slotrank].val_320c + full_shift;
1001
1002 if (shift < 0)
1003 shift = 0;
1004
1005 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001006 post_timA_min_high = MIN(post_timA_min_high,
1007 (ctrl->timings[channel][slotrank].lanes[lane].
1008 timA + shift) >> 6);
1009 pre_timA_min_high = MIN(pre_timA_min_high,
1010 ctrl->timings[channel][slotrank].lanes[lane].
1011 timA >> 6);
1012 post_timA_max_high = MAX(post_timA_max_high,
1013 (ctrl->timings[channel][slotrank].lanes[lane].
1014 timA + shift) >> 6);
1015 pre_timA_max_high = MAX(pre_timA_max_high,
1016 ctrl->timings[channel][slotrank].lanes[lane].
1017 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001018 }
1019
1020 if (pre_timA_max_high - pre_timA_min_high <
1021 post_timA_max_high - post_timA_min_high)
1022 shift_402x = +1;
1023 else if (pre_timA_max_high - pre_timA_min_high >
1024 post_timA_max_high - post_timA_min_high)
1025 shift_402x = -1;
1026
1027 reg_4028 |=
1028 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1029 post_timA_min_high) << (4 * slotrank);
1030 reg_4024 |=
1031 (ctrl->timings[channel][slotrank].val_4024 +
1032 shift_402x) << (8 * slotrank);
1033
1034 FOR_ALL_LANES {
1035 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1036 4 * slotrank)
1037 =
1038 (((ctrl->timings[channel][slotrank].lanes[lane].
1039 timA + shift) & 0x3f)
1040 |
1041 ((ctrl->timings[channel][slotrank].lanes[lane].
1042 rising + shift) << 8)
1043 |
1044 (((ctrl->timings[channel][slotrank].lanes[lane].
1045 timA + shift -
1046 (post_timA_min_high << 6)) & 0x1c0) << 10)
1047 | ((ctrl->timings[channel][slotrank].lanes[lane].
1048 falling + shift) << 20));
1049
1050 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1051 4 * slotrank)
1052 =
1053 (((ctrl->timings[channel][slotrank].lanes[lane].
1054 timC + shift) & 0x3f)
1055 |
1056 (((ctrl->timings[channel][slotrank].lanes[lane].
1057 timB + shift) & 0x3f) << 8)
1058 |
1059 (((ctrl->timings[channel][slotrank].lanes[lane].
1060 timB + shift) & 0x1c0) << 9)
1061 |
1062 (((ctrl->timings[channel][slotrank].lanes[lane].
1063 timC + shift) & 0x40) << 13));
1064 }
1065 }
1066 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
1067 MCHBAR32(0x4028 + 0x400 * channel) = reg_4028;
1068}
1069
1070static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1071{
1072 wait_428c(channel);
1073
1074 /* DRAM command MRS
1075 * write MR3 MPR enable
1076 * in this mode only RD and RDA are allowed
1077 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001078 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1079 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1080 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1081 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001082
1083 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001084 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1085 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1086 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1087 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001088
1089 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001090 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1091 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1092 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1093 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001094
1095 /* DRAM command MRS
1096 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001097 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1098 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1099 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1100 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001101
Felix Held9cf1dd22018-07-31 14:52:40 +02001102 // execute command queue
1103 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001104
1105 wait_428c(channel);
1106}
1107
1108static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1109 int lane)
1110{
1111 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001112 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001113 ((timA / 32) & 1) * 4)
1114 >> (timA % 32)) & 1);
1115}
1116
1117struct run {
1118 int middle;
1119 int end;
1120 int start;
1121 int all;
1122 int length;
1123};
1124
1125static struct run get_longest_zero_run(int *seq, int sz)
1126{
1127 int i, ls;
1128 int bl = 0, bs = 0;
1129 struct run ret;
1130
1131 ls = 0;
1132 for (i = 0; i < 2 * sz; i++)
1133 if (seq[i % sz]) {
1134 if (i - ls > bl) {
1135 bl = i - ls;
1136 bs = ls;
1137 }
1138 ls = i + 1;
1139 }
1140 if (bl == 0) {
1141 ret.middle = sz / 2;
1142 ret.start = 0;
1143 ret.end = sz;
1144 ret.all = 1;
1145 return ret;
1146 }
1147
1148 ret.start = bs % sz;
1149 ret.end = (bs + bl - 1) % sz;
1150 ret.middle = (bs + (bl - 1) / 2) % sz;
1151 ret.length = bl;
1152 ret.all = 0;
1153
1154 return ret;
1155}
1156
1157static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1158 int slotrank, int *upperA)
1159{
1160 int timA;
1161 int statistics[NUM_LANES][128];
1162 int lane;
1163
1164 for (timA = 0; timA < 128; timA++) {
1165 FOR_ALL_LANES {
1166 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1167 }
1168 program_timings(ctrl, channel);
1169
1170 test_timA(ctrl, channel, slotrank);
1171
1172 FOR_ALL_LANES {
1173 statistics[lane][timA] =
1174 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001175 }
1176 }
1177 FOR_ALL_LANES {
1178 struct run rn = get_longest_zero_run(statistics[lane], 128);
1179 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1180 upperA[lane] = rn.end;
1181 if (upperA[lane] < rn.middle)
1182 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001183 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001184 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001185 }
1186}
1187
1188static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1189 int *upperA)
1190{
1191 int timA_delta;
1192 int statistics[NUM_LANES][51];
1193 int lane, i;
1194
1195 memset(statistics, 0, sizeof(statistics));
1196
1197 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1198 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1199 timA = upperA[lane] + timA_delta + 0x40;
1200 program_timings(ctrl, channel);
1201
1202 for (i = 0; i < 100; i++) {
1203 test_timA(ctrl, channel, slotrank);
1204 FOR_ALL_LANES {
1205 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001206 does_lane_work(ctrl, channel, slotrank,
1207 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001208 }
1209 }
1210 }
1211 FOR_ALL_LANES {
1212 int last_zero, first_all;
1213
1214 for (last_zero = -25; last_zero <= 25; last_zero++)
1215 if (statistics[lane][last_zero + 25])
1216 break;
1217 last_zero--;
1218 for (first_all = -25; first_all <= 25; first_all++)
1219 if (statistics[lane][first_all + 25] == 100)
1220 break;
1221
1222 printram("lane %d: %d, %d\n", lane, last_zero,
1223 first_all);
1224
1225 ctrl->timings[channel][slotrank].lanes[lane].timA =
1226 (last_zero + first_all) / 2 + upperA[lane];
1227 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1228 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1229 }
1230}
1231
1232static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1233 int *upperA)
1234{
1235 int works[NUM_LANES];
1236 int lane;
1237 while (1) {
1238 int all_works = 1, some_works = 0;
1239 program_timings(ctrl, channel);
1240 test_timA(ctrl, channel, slotrank);
1241 FOR_ALL_LANES {
1242 works[lane] =
1243 !does_lane_work(ctrl, channel, slotrank, lane);
1244 if (works[lane])
1245 some_works = 1;
1246 else
1247 all_works = 0;
1248 }
1249 if (all_works)
1250 return 0;
1251 if (!some_works) {
1252 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1253 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1254 channel, slotrank);
1255 return MAKE_ERR;
1256 }
1257 ctrl->timings[channel][slotrank].val_4024 -= 2;
1258 printram("4024 -= 2;\n");
1259 continue;
1260 }
1261 ctrl->timings[channel][slotrank].val_4028 += 2;
1262 printram("4028 += 2;\n");
1263 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1264 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1265 channel, slotrank);
1266 return MAKE_ERR;
1267 }
1268 FOR_ALL_LANES if (works[lane]) {
1269 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1270 128;
1271 upperA[lane] += 128;
1272 printram("increment %d, %d, %d\n", channel,
1273 slotrank, lane);
1274 }
1275 }
1276 return 0;
1277}
1278
1279struct timA_minmax {
1280 int timA_min_high, timA_max_high;
1281};
1282
1283static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1284 struct timA_minmax *mnmx)
1285{
1286 int lane;
1287 mnmx->timA_min_high = 7;
1288 mnmx->timA_max_high = 0;
1289
1290 FOR_ALL_LANES {
1291 if (mnmx->timA_min_high >
1292 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1293 mnmx->timA_min_high =
1294 (ctrl->timings[channel][slotrank].lanes[lane].
1295 timA >> 6);
1296 if (mnmx->timA_max_high <
1297 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1298 mnmx->timA_max_high =
1299 (ctrl->timings[channel][slotrank].lanes[lane].
1300 timA >> 6);
1301 }
1302}
1303
1304static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1305 struct timA_minmax *mnmx)
1306{
1307 struct timA_minmax post;
1308 int shift_402x = 0;
1309
1310 /* Get changed maxima. */
1311 pre_timA_change(ctrl, channel, slotrank, &post);
1312
1313 if (mnmx->timA_max_high - mnmx->timA_min_high <
1314 post.timA_max_high - post.timA_min_high)
1315 shift_402x = +1;
1316 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1317 post.timA_max_high - post.timA_min_high)
1318 shift_402x = -1;
1319 else
1320 shift_402x = 0;
1321
1322 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1323 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1324 printram("4024 += %d;\n", shift_402x);
1325 printram("4028 += %d;\n", shift_402x);
1326}
1327
1328/* Compensate the skew between DQS and DQs.
1329 * To ease PCB design a small skew between Data Strobe signals and
1330 * Data Signals is allowed.
1331 * The controller has to measure and compensate this skew for every byte-lane.
1332 * By delaying either all DQs signals or DQS signal, a full phase
1333 * shift can be introduced.
1334 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1335 *
1336 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1337 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1338 * The memory controller iterates over all possible values to do a full phase shift
1339 * and issues read commands.
1340 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1341 * 0xFF 0x00 0xFF ...
1342 * Once the controller has detected this pattern a bit in the result register is
1343 * set for the current phase shift.
1344 */
1345int read_training(ramctr_timing * ctrl)
1346{
1347 int channel, slotrank, lane;
1348 int err;
1349
1350 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1351 int all_high, some_high;
1352 int upperA[NUM_LANES];
1353 struct timA_minmax mnmx;
1354
Felix Held2bb3cdf2018-07-28 00:23:59 +02001355 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001356
Felix Held2bb3cdf2018-07-28 00:23:59 +02001357 /* DRAM command PREA */
1358 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1359 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1360 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1361 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001362
1363 // execute command queue
1364 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001365
Felix Held2bb3cdf2018-07-28 00:23:59 +02001366 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001367
Felix Held2bb3cdf2018-07-28 00:23:59 +02001368 ctrl->timings[channel][slotrank].val_4028 = 4;
1369 ctrl->timings[channel][slotrank].val_4024 = 55;
1370 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001371
Felix Held2bb3cdf2018-07-28 00:23:59 +02001372 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001373
Felix Held2bb3cdf2018-07-28 00:23:59 +02001374 all_high = 1;
1375 some_high = 0;
1376 FOR_ALL_LANES {
1377 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1378 0x40)
1379 some_high = 1;
1380 else
1381 all_high = 0;
1382 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001383
1384 if (all_high) {
1385 ctrl->timings[channel][slotrank].val_4028--;
1386 printram("4028--;\n");
1387 FOR_ALL_LANES {
1388 ctrl->timings[channel][slotrank].lanes[lane].
1389 timA -= 0x40;
1390 upperA[lane] -= 0x40;
1391
1392 }
1393 } else if (some_high) {
1394 ctrl->timings[channel][slotrank].val_4024++;
1395 ctrl->timings[channel][slotrank].val_4028++;
1396 printram("4024++;\n");
1397 printram("4028++;\n");
1398 }
1399
1400 program_timings(ctrl, channel);
1401
1402 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1403
1404 err = discover_402x(ctrl, channel, slotrank, upperA);
1405 if (err)
1406 return err;
1407
1408 post_timA_change(ctrl, channel, slotrank, &mnmx);
1409 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1410
1411 discover_timA_fine(ctrl, channel, slotrank, upperA);
1412
1413 post_timA_change(ctrl, channel, slotrank, &mnmx);
1414 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1415
1416 FOR_ALL_LANES {
1417 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1418 }
1419 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1420 printram("4028 -= %d;\n", mnmx.timA_min_high);
1421
1422 post_timA_change(ctrl, channel, slotrank, &mnmx);
1423
1424 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1425 ctrl->timings[channel][slotrank].val_4024,
1426 ctrl->timings[channel][slotrank].val_4028);
1427
1428 printram("final results:\n");
1429 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001430 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1431 lane,
1432 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001433
Felix Held2bb3cdf2018-07-28 00:23:59 +02001434 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001435
1436 toggle_io_reset();
1437 }
1438
1439 FOR_ALL_POPULATED_CHANNELS {
1440 program_timings(ctrl, channel);
1441 }
1442 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001443 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001444 }
1445 return 0;
1446}
1447
1448static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1449{
1450 int lane;
1451
1452 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001453 volatile u32 tmp;
1454 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
1455 tmp = MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001456 }
1457
1458 wait_428c(channel);
1459
1460 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001461 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1462 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001463 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001464 | 4 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001465 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001466 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001467
1468 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001469 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1470 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1471 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1472 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001473
1474 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001475 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1476 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1477 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1478 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001479
1480 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001481 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1482 MCHBAR32(0x423c + 0x400 * channel) =
1483 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1484 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1485 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001486
Felix Held9cf1dd22018-07-31 14:52:40 +02001487 // execute command queue
1488 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001489
1490 wait_428c(channel);
1491
1492 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001493 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1494 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1495 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1496 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001497
1498 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001499 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1500 MCHBAR32(0x4234 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001501 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001502 | 8 | (ctrl->CAS << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001503 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001504 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001505
1506 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001507 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1508 MCHBAR32(0x4238 + 0x400 * channel) =
1509 0x40011f4 | (max(ctrl->tRTP, 8) << 16);
1510 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1511 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001512
1513 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001514 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1515 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1516 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1517 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001518
1519 // execute command queue
1520 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1521
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001522 wait_428c(channel);
1523}
1524
1525static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1526{
1527 int timC;
1528 int statistics[NUM_LANES][MAX_TIMC + 1];
1529 int lane;
1530
1531 wait_428c(channel);
1532
1533 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001534 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1535 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
Felix Held9fe248f2018-07-31 20:59:45 +02001536 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001537 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001538
1539 // execute command queue
1540 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001541
1542 for (timC = 0; timC <= MAX_TIMC; timC++) {
1543 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1544 timC = timC;
1545 program_timings(ctrl, channel);
1546
1547 test_timC(ctrl, channel, slotrank);
1548
1549 FOR_ALL_LANES {
1550 statistics[lane][timC] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001551 MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001552 }
1553 }
1554 FOR_ALL_LANES {
1555 struct run rn =
1556 get_longest_zero_run(statistics[lane], MAX_TIMC + 1);
1557 ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
1558 if (rn.all) {
1559 printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
1560 channel, slotrank, lane);
1561 return MAKE_ERR;
1562 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001563 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001564 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001565 }
1566 return 0;
1567}
1568
1569static int get_precedening_channels(ramctr_timing * ctrl, int target_channel)
1570{
1571 int channel, ret = 0;
1572 FOR_ALL_POPULATED_CHANNELS if (channel < target_channel)
1573 ret++;
1574 return ret;
1575}
1576
1577static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b)
1578{
1579 unsigned j;
1580 unsigned channel_offset =
1581 get_precedening_channels(ctrl, channel) * 0x40;
1582 for (j = 0; j < 16; j++)
1583 write32((void *)(0x04000000 + channel_offset + 4 * j), j & 2 ? b : a);
1584 sfence();
1585}
1586
1587static int num_of_channels(const ramctr_timing * ctrl)
1588{
1589 int ret = 0;
1590 int channel;
1591 FOR_ALL_POPULATED_CHANNELS ret++;
1592 return ret;
1593}
1594
1595static void fill_pattern1(ramctr_timing * ctrl, int channel)
1596{
1597 unsigned j;
1598 unsigned channel_offset =
1599 get_precedening_channels(ctrl, channel) * 0x40;
1600 unsigned channel_step = 0x40 * num_of_channels(ctrl);
1601 for (j = 0; j < 16; j++)
1602 write32((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff);
1603 for (j = 0; j < 16; j++)
1604 write32((void *)(0x04000000 + channel_offset + channel_step + j * 4), 0);
1605 sfence();
1606}
1607
1608static void precharge(ramctr_timing * ctrl)
1609{
1610 int channel, slotrank, lane;
1611
1612 FOR_ALL_POPULATED_CHANNELS {
1613 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1614 ctrl->timings[channel][slotrank].lanes[lane].falling =
1615 16;
1616 ctrl->timings[channel][slotrank].lanes[lane].rising =
1617 16;
1618 }
1619
1620 program_timings(ctrl, channel);
1621
1622 FOR_ALL_POPULATED_RANKS {
1623 wait_428c(channel);
1624
1625 /* DRAM command MRS
1626 * write MR3 MPR enable
1627 * in this mode only RD and RDA are allowed
1628 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001629 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1630 MCHBAR32(0x4230 + 0x400 * channel) =
1631 0xc01 | (ctrl->tMOD << 16);
1632 MCHBAR32(0x4200 + 0x400 * channel) =
1633 (slotrank << 24) | 0x360004;
1634 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001635
1636 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001637 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1638 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1639 MCHBAR32(0x4204 + 0x400 * channel) =
1640 (slotrank << 24) | 0;
1641 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001642
1643 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001644 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1645 MCHBAR32(0x4238 + 0x400 * channel) =
1646 0x1001 | ((ctrl->CAS + 8) << 16);
1647 MCHBAR32(0x4208 + 0x400 * channel) =
1648 (slotrank << 24) | 0x60000;
1649 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001650
1651 /* DRAM command MRS
1652 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001653 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1654 MCHBAR32(0x423c + 0x400 * channel) =
1655 0xc01 | (ctrl->tMOD << 16);
1656 MCHBAR32(0x420c + 0x400 * channel) =
1657 (slotrank << 24) | 0x360000;
1658 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001659
1660 // execute command queue
1661 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001662
1663 wait_428c(channel);
1664 }
1665
1666 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1667 ctrl->timings[channel][slotrank].lanes[lane].falling =
1668 48;
1669 ctrl->timings[channel][slotrank].lanes[lane].rising =
1670 48;
1671 }
1672
1673 program_timings(ctrl, channel);
1674
1675 FOR_ALL_POPULATED_RANKS {
1676 wait_428c(channel);
1677 /* DRAM command MRS
1678 * write MR3 MPR enable
1679 * in this mode only RD and RDA are allowed
1680 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001681 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1682 MCHBAR32(0x4230 + 0x400 * channel) =
1683 0xc01 | (ctrl->tMOD << 16);
1684 MCHBAR32(0x4200 + 0x400 * channel) =
1685 (slotrank << 24) | 0x360004;
1686 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001687
1688 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001689 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1690 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1691 MCHBAR32(0x4204 + 0x400 * channel) =
1692 (slotrank << 24) | 0;
1693 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001694
1695 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001696 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1697 MCHBAR32(0x4238 + 0x400 * channel) =
1698 0x1001 | ((ctrl->CAS + 8) << 16);
1699 MCHBAR32(0x4208 + 0x400 * channel) =
1700 (slotrank << 24) | 0x60000;
1701 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001702
1703 /* DRAM command MRS
1704 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001705 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1706 MCHBAR32(0x423c + 0x400 * channel) =
1707 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001708 MCHBAR32(0x420c + 0x400 * channel) =
1709 (slotrank << 24) | 0x360000;
1710 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001711
Felix Held9cf1dd22018-07-31 14:52:40 +02001712 // execute command queue
1713 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1714
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001715 wait_428c(channel);
1716 }
1717 }
1718}
1719
1720static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1721{
1722 /* enable DQs on this slotrank */
1723 write_mrreg(ctrl, channel, slotrank, 1,
1724 0x80 | make_mr1(ctrl, slotrank, channel));
1725
1726 wait_428c(channel);
1727 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001728 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1729 MCHBAR32(0x4230 + 0x400 * channel) =
1730 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1731 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1732 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001733
1734 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001735 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1736 MCHBAR32(0x4234 + 0x400 * channel) =
1737 0x4000c01 | ((ctrl->CAS + 38) << 16);
1738 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1739 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001740
Felix Held9cf1dd22018-07-31 14:52:40 +02001741 // execute command queue
1742 MCHBAR32(0x400 * channel + 0x4284) = RUN_QUEUE_4284(2);
1743
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001744 wait_428c(channel);
1745
1746 /* disable DQs on this slotrank */
1747 write_mrreg(ctrl, channel, slotrank, 1,
1748 0x1080 | make_mr1(ctrl, slotrank, channel));
1749}
1750
1751static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1752{
1753 int timB;
1754 int statistics[NUM_LANES][128];
1755 int lane;
1756
Felix Held2bb3cdf2018-07-28 00:23:59 +02001757 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001758
1759 for (timB = 0; timB < 128; timB++) {
1760 FOR_ALL_LANES {
1761 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1762 }
1763 program_timings(ctrl, channel);
1764
1765 test_timB(ctrl, channel, slotrank);
1766
1767 FOR_ALL_LANES {
1768 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001769 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001770 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1771 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001772 }
1773 }
1774 FOR_ALL_LANES {
1775 struct run rn = get_longest_zero_run(statistics[lane], 128);
1776 /* timC is a direct function of timB's 6 LSBs.
1777 * Some tests increments the value of timB by a small value,
1778 * which might cause the 6bit value to overflow, if it's close
1779 * to 0x3F. Increment the value by a small offset if it's likely
1780 * to overflow, to make sure it won't overflow while running
1781 * tests and bricks the system due to a non matching timC.
1782 *
1783 * TODO: find out why some tests (edge write discovery)
1784 * increment timB. */
1785 if ((rn.start & 0x3F) == 0x3E)
1786 rn.start += 2;
1787 else if ((rn.start & 0x3F) == 0x3F)
1788 rn.start += 1;
1789 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1790 if (rn.all) {
1791 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1792 channel, slotrank, lane);
1793 return MAKE_ERR;
1794 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001795 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1796 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001797 }
1798 return 0;
1799}
1800
1801static int get_timB_high_adjust(u64 val)
1802{
1803 int i;
1804
1805 /* good */
1806 if (val == 0xffffffffffffffffLL)
1807 return 0;
1808
1809 if (val >= 0xf000000000000000LL) {
1810 /* needs negative adjustment */
1811 for (i = 0; i < 8; i++)
1812 if (val << (8 * (7 - i) + 4))
1813 return -i;
1814 } else {
1815 /* needs positive adjustment */
1816 for (i = 0; i < 8; i++)
1817 if (val >> (8 * (7 - i) + 4))
1818 return i;
1819 }
1820 return 8;
1821}
1822
1823static void adjust_high_timB(ramctr_timing * ctrl)
1824{
1825 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001826 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001827 FOR_ALL_POPULATED_CHANNELS {
1828 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001829 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001830 }
1831 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1832
Felix Held2bb3cdf2018-07-28 00:23:59 +02001833 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001834
1835 wait_428c(channel);
1836
1837 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001838 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1839 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1840 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1841 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001842
1843 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001844 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1845 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1846 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1847 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001848
1849 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001850 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1851 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1852 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1853 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001854
1855 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001856 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1857 MCHBAR32(0x423c + 0x400 * channel) =
1858 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1859 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1860 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001861
Felix Held9cf1dd22018-07-31 14:52:40 +02001862 // execute command queue
1863 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001864
1865 wait_428c(channel);
1866
1867 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001868 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1869 MCHBAR32(0x4230 + 0x400 * channel) =
1870 0xc01 | ((ctrl->tRP) << 16);
1871 MCHBAR32(0x4200 + 0x400 * channel) =
1872 (slotrank << 24) | 0x60400;
1873 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001874
1875 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001876 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1877 MCHBAR32(0x4234 + 0x400 * channel) =
1878 0xc01 | ((ctrl->tRCD) << 16);
1879 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1880 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001881
1882 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001883 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1884 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001885 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001886 ctrl->timings[channel][slotrank].val_4028) << 16);
1887 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1888 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001889
Felix Held9cf1dd22018-07-31 14:52:40 +02001890 // execute command queue
1891 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
1892
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001893 wait_428c(channel);
1894 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001895 u64 res = MCHBAR32(lane_registers[lane] +
1896 0x100 * channel + 4);
1897 res |= ((u64) MCHBAR32(lane_registers[lane] +
1898 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001899 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1900 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1901 get_timB_high_adjust(res) * 64;
1902
1903 printram("High adjust %d:%016llx\n", lane, res);
1904 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1905 slotrank, lane, old,
1906 ctrl->timings[channel][slotrank].lanes[lane].
1907 timB);
1908 }
1909 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001910 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001911}
1912
1913static void write_op(ramctr_timing * ctrl, int channel)
1914{
1915 int slotrank;
1916
1917 wait_428c(channel);
1918
1919 /* choose an existing rank. */
1920 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1921
1922 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001923 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1924 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001925 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001926 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001927
Felix Held9cf1dd22018-07-31 14:52:40 +02001928 // execute command queue
1929 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
1930
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001931 wait_428c(channel);
1932}
1933
1934/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1935 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1936 * the chips at different times with respect to command, address and
1937 * clock signals.
1938 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1939 * shift can be introduced.
1940 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1941 *
1942 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1943 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1944 * sampled value on the data lanes (DQs).
1945 */
1946int write_training(ramctr_timing * ctrl)
1947{
1948 int channel, slotrank, lane;
1949 int err;
1950
1951 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001952 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001953
1954 FOR_ALL_POPULATED_CHANNELS {
1955 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001956 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001957 }
1958
1959 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001960 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001961 FOR_ALL_POPULATED_CHANNELS {
1962 write_op(ctrl, channel);
1963 }
1964
1965 /* enable write leveling on all ranks
1966 * disable all DQ outputs
1967 * only NOP is allowed in this mode */
1968 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02001969 FOR_ALL_POPULATED_RANKS
1970 write_mrreg(ctrl, channel, slotrank, 1,
1971 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001972
Felix Held2bb3cdf2018-07-28 00:23:59 +02001973 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001974
1975 toggle_io_reset();
1976
1977 /* set any valid value for timB, it gets corrected later */
1978 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1979 err = discover_timB(ctrl, channel, slotrank);
1980 if (err)
1981 return err;
1982 }
1983
1984 /* disable write leveling on all ranks */
1985 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
1986 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02001987 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001988
Felix Held2bb3cdf2018-07-28 00:23:59 +02001989 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001990
1991 FOR_ALL_POPULATED_CHANNELS
1992 wait_428c(channel);
1993
1994 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02001995 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001996
1997 FOR_ALL_POPULATED_CHANNELS {
Felix Heldb802c072018-07-29 21:46:19 +02001998 volatile u32 tmp;
Felix Held2463aa92018-07-29 21:37:55 +02001999 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002000 tmp = MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002001 wait_428c(channel);
2002
2003 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002004 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2005 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2006 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2007 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002008
Felix Held9cf1dd22018-07-31 14:52:40 +02002009 // execute command queue
2010 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2011
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002012 wait_428c(channel);
2013 }
2014
2015 toggle_io_reset();
2016
2017 printram("CPE\n");
2018 precharge(ctrl);
2019 printram("CPF\n");
2020
2021 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002022 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002023 }
2024
2025 FOR_ALL_POPULATED_CHANNELS {
2026 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002027 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002028 }
2029
2030 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2031 err = discover_timC(ctrl, channel, slotrank);
2032 if (err)
2033 return err;
2034 }
2035
2036 FOR_ALL_POPULATED_CHANNELS
2037 program_timings(ctrl, channel);
2038
2039 /* measure and adjust timB timings */
2040 adjust_high_timB(ctrl);
2041
2042 FOR_ALL_POPULATED_CHANNELS
2043 program_timings(ctrl, channel);
2044
2045 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002046 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002047 }
2048 return 0;
2049}
2050
2051static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2052{
2053 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2054 int timC_delta;
2055 int lanes_ok = 0;
2056 int ctr = 0;
2057 int lane;
2058
2059 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2060 FOR_ALL_LANES {
2061 ctrl->timings[channel][slotrank].lanes[lane].timC =
2062 saved_rt.lanes[lane].timC + timC_delta;
2063 }
2064 program_timings(ctrl, channel);
2065 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002066 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002067 }
2068
Felix Held2bb3cdf2018-07-28 00:23:59 +02002069 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002070
2071 wait_428c(channel);
2072 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002073 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2074 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002075 ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002076 | 8 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002077 MCHBAR32(0x4200 + 0x400 * channel) =
2078 (slotrank << 24) | ctr | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002079 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Felix Held9fe248f2018-07-31 20:59:45 +02002080
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002081 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002082 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2083 MCHBAR32(0x4234 + 0x400 * channel) =
2084 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2085 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2086 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2087 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002088
2089 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002090 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2091 MCHBAR32(0x4238 + 0x400 * channel) =
2092 0x4001020 | (max(ctrl->tRTP, 8) << 16);
2093 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2094 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2095 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002096
2097 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002098 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2099 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2100 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2101 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002102
Felix Held9cf1dd22018-07-31 14:52:40 +02002103 // execute command queue
2104 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2105
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002106 wait_428c(channel);
2107 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002108 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002109
2110 if (r32 == 0)
2111 lanes_ok |= 1 << lane;
2112 }
2113 ctr++;
2114 if (lanes_ok == ((1 << NUM_LANES) - 1))
2115 break;
2116 }
2117
2118 ctrl->timings[channel][slotrank] = saved_rt;
2119
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002120 return lanes_ok != ((1 << NUM_LANES) - 1);
2121}
2122
2123#include "raminit_patterns.h"
2124
2125static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2126{
2127 unsigned i, j;
2128 unsigned channel_offset =
2129 get_precedening_channels(ctrl, channel) * 0x40;
2130 unsigned channel_step = 0x40 * num_of_channels(ctrl);
2131
2132 if (patno) {
2133 u8 base8 = 0x80 >> ((patno - 1) % 8);
2134 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2135 for (i = 0; i < 32; i++) {
2136 for (j = 0; j < 16; j++) {
2137 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2138 if (invert[patno - 1][i] & (1 << (j / 2)))
2139 val = ~val;
2140 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2141 j * 4), val);
2142 }
2143 }
2144
2145 } else {
2146 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2147 for (j = 0; j < 16; j++)
2148 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2149 j * 4), pattern[i][j]);
2150 }
2151 sfence();
2152 }
2153}
2154
2155static void reprogram_320c(ramctr_timing * ctrl)
2156{
2157 int channel, slotrank;
2158
2159 FOR_ALL_POPULATED_CHANNELS {
2160 wait_428c(channel);
2161
2162 /* choose an existing rank. */
2163 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2164
2165 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002166 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2167 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002168 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002169 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002170
Felix Held9cf1dd22018-07-31 14:52:40 +02002171 // execute command queue
2172 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2173
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002174 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002175 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002176 }
2177
2178 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002179 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002180 FOR_ALL_POPULATED_CHANNELS {
2181 wait_428c(channel);
2182
2183 /* choose an existing rank. */
2184 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2185
2186 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002187 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2188 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002189 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002190 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002191
Felix Held9cf1dd22018-07-31 14:52:40 +02002192 // execute command queue
2193 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2194
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002195 wait_428c(channel);
2196 }
2197
2198 /* jedec reset */
2199 dram_jedecreset(ctrl);
2200 /* mrs commands. */
2201 dram_mrscommands(ctrl);
2202
2203 toggle_io_reset();
2204}
2205
2206#define MIN_C320C_LEN 13
2207
2208static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2209{
2210 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2211 int slotrank;
2212 int c320c;
2213 int stat[NUM_SLOTRANKS][256];
2214 int delta = 0;
2215
2216 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2217
2218 FOR_ALL_POPULATED_RANKS {
2219 saved_timings[channel][slotrank] =
2220 ctrl->timings[channel][slotrank];
2221 }
2222
2223 ctrl->cmd_stretch[channel] = cmd_stretch;
2224
2225 MCHBAR32(0x4004 + 0x400 * channel) =
2226 ctrl->tRRD
2227 | (ctrl->tRTP << 4)
2228 | (ctrl->tCKE << 8)
2229 | (ctrl->tWTR << 12)
2230 | (ctrl->tFAW << 16)
2231 | (ctrl->tWR << 24)
2232 | (ctrl->cmd_stretch[channel] << 30);
2233
2234 if (ctrl->cmd_stretch[channel] == 2)
2235 delta = 2;
2236 else if (ctrl->cmd_stretch[channel] == 0)
2237 delta = 4;
2238
2239 FOR_ALL_POPULATED_RANKS {
2240 ctrl->timings[channel][slotrank].val_4024 -= delta;
2241 }
2242
2243 for (c320c = -127; c320c <= 127; c320c++) {
2244 FOR_ALL_POPULATED_RANKS {
2245 ctrl->timings[channel][slotrank].val_320c = c320c;
2246 }
2247 program_timings(ctrl, channel);
2248 reprogram_320c(ctrl);
2249 FOR_ALL_POPULATED_RANKS {
2250 stat[slotrank][c320c + 127] =
2251 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002252 }
2253 }
2254 FOR_ALL_POPULATED_RANKS {
2255 struct run rn =
2256 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002257 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002258 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2259 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002260 if (rn.all || rn.length < MIN_C320C_LEN) {
2261 FOR_ALL_POPULATED_RANKS {
2262 ctrl->timings[channel][slotrank] =
2263 saved_timings[channel][slotrank];
2264 }
2265 return MAKE_ERR;
2266 }
2267 }
2268
2269 return 0;
2270}
2271
2272/* Adjust CMD phase shift and try multiple command rates.
2273 * A command rate of 2T doubles the time needed for address and
2274 * command decode. */
2275int command_training(ramctr_timing *ctrl)
2276{
2277 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002278
2279 FOR_ALL_POPULATED_CHANNELS {
2280 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002281 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002282 }
2283
2284 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002285 int cmdrate, err;
2286
2287 /*
2288 * Dual DIMM per channel:
2289 * Issue: While c320c discovery seems to succeed raminit
2290 * will fail in write training.
2291 * Workaround: Skip 1T in dual DIMM mode, that's only
2292 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002293 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2294 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002295 *
2296 * Single DIMM per channel:
2297 * Try command rate 1T and 2T
2298 */
2299 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002300 if (ctrl->tCMD)
2301 /* XMP gives the CMD rate in clock ticks, not ns */
2302 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002303
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002304 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002305 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2306
2307 if (!err)
2308 break;
2309 }
2310
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002311 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002312 printk(BIOS_EMERG, "c320c discovery failed\n");
2313 return err;
2314 }
2315
2316 printram("Using CMD rate %uT on channel %u\n",
2317 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002318 }
2319
2320 FOR_ALL_POPULATED_CHANNELS
2321 program_timings(ctrl, channel);
2322
2323 reprogram_320c(ctrl);
2324 return 0;
2325}
2326
2327
2328static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2329 int *edges)
2330{
2331 int edge;
2332 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2333 int lane;
2334
2335 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2336 FOR_ALL_LANES {
2337 ctrl->timings[channel][slotrank].lanes[lane].rising =
2338 edge;
2339 ctrl->timings[channel][slotrank].lanes[lane].falling =
2340 edge;
2341 }
2342 program_timings(ctrl, channel);
2343
2344 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002345 volatile u32 tmp;
2346 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
2347 tmp = MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002348 }
2349
2350 wait_428c(channel);
2351 /* DRAM command MRS
2352 * write MR3 MPR enable
2353 * in this mode only RD and RDA are allowed
2354 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002355 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002356 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002357 MCHBAR32(0x4200 + 0x400 * channel) =
2358 (slotrank << 24) | 0x360004;
2359 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002360
2361 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002362 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2363 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2364 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2365 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002366
2367 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002368 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2369 MCHBAR32(0x4238 + 0x400 * channel) =
2370 0x1001 | ((ctrl->CAS + 8) << 16);
2371 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2372 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002373
2374 /* DRAM command MRS
2375 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002376 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2377 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2378 MCHBAR32(0x420c + 0x400 * channel) =
2379 (slotrank << 24) | 0x360000;
2380 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002381
Felix Held9cf1dd22018-07-31 14:52:40 +02002382 // execute command queue
2383 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002384
2385 wait_428c(channel);
2386
2387 FOR_ALL_LANES {
2388 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002389 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002390 }
2391 }
2392 FOR_ALL_LANES {
2393 struct run rn =
2394 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2395 edges[lane] = rn.middle;
2396 if (rn.all) {
2397 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2398 channel, slotrank, lane);
2399 return MAKE_ERR;
2400 }
2401 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2402 lane, edges[lane]);
2403 }
2404 return 0;
2405}
2406
2407int discover_edges(ramctr_timing *ctrl)
2408{
2409 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2410 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2411 int channel, slotrank, lane;
2412 int err;
2413
Felix Held2bb3cdf2018-07-28 00:23:59 +02002414 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002415
2416 toggle_io_reset();
2417
2418 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002419 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002420 }
2421
2422 FOR_ALL_POPULATED_CHANNELS {
2423 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002424 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002425 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002426 volatile u32 tmp;
2427 tmp = MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002428 }
2429
2430 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2431 ctrl->timings[channel][slotrank].lanes[lane].falling =
2432 16;
2433 ctrl->timings[channel][slotrank].lanes[lane].rising =
2434 16;
2435 }
2436
2437 program_timings(ctrl, channel);
2438
2439 FOR_ALL_POPULATED_RANKS {
2440 wait_428c(channel);
2441
2442 /* DRAM command MRS
2443 * MR3 enable MPR
2444 * write MR3 MPR enable
2445 * in this mode only RD and RDA are allowed
2446 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002447 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2448 MCHBAR32(0x4230 + 0x400 * channel) =
2449 0xc01 | (ctrl->tMOD << 16);
2450 MCHBAR32(0x4200 + 0x400 * channel) =
2451 (slotrank << 24) | 0x360004;
2452 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002453
2454 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002455 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2456 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2457 MCHBAR32(0x4204 + 0x400 * channel) =
2458 (slotrank << 24) | 0;
2459 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002460
2461 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002462 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2463 MCHBAR32(0x4238 + 0x400 * channel) =
2464 0x1001 | ((ctrl->CAS + 8) << 16);
2465 MCHBAR32(0x4208 + 0x400 * channel) =
2466 (slotrank << 24) | 0x60000;
2467 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002468
2469 /* DRAM command MRS
2470 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002471 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2472 MCHBAR32(0x423c + 0x400 * channel) =
2473 0xc01 | (ctrl->tMOD << 16);
2474 MCHBAR32(0x420c + 0x400 * channel) =
2475 (slotrank << 24) | 0x360000;
2476 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02002477
2478 // execute command queue
2479 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002480
2481 wait_428c(channel);
2482 }
2483
2484 /* XXX: check any measured value ? */
2485
2486 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2487 ctrl->timings[channel][slotrank].lanes[lane].falling =
2488 48;
2489 ctrl->timings[channel][slotrank].lanes[lane].rising =
2490 48;
2491 }
2492
2493 program_timings(ctrl, channel);
2494
2495 FOR_ALL_POPULATED_RANKS {
2496 wait_428c(channel);
2497
2498 /* DRAM command MRS
2499 * MR3 enable MPR
2500 * write MR3 MPR enable
2501 * in this mode only RD and RDA are allowed
2502 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002503 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2504 MCHBAR32(0x4230 + 0x400 * channel) =
2505 0xc01 | (ctrl->tMOD << 16);
2506 MCHBAR32(0x4200 + 0x400 * channel) =
2507 (slotrank << 24) | 0x360004;
2508 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002509
2510 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002511 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2512 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2513 MCHBAR32(0x4204 + 0x400 * channel) =
2514 (slotrank << 24) | 0;
2515 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002516
2517 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002518 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2519 MCHBAR32(0x4238 + 0x400 * channel) =
2520 0x1001 | ((ctrl->CAS + 8) << 16);
2521 MCHBAR32(0x4208 + 0x400 * channel) =
2522 (slotrank << 24) | 0x60000;
2523 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002524
2525 /* DRAM command MRS
2526 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002527 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2528 MCHBAR32(0x423c + 0x400 * channel) =
2529 0xc01 | (ctrl->tMOD << 16);
2530 MCHBAR32(0x420c + 0x400 * channel) =
2531 (slotrank << 24) | 0x360000;
2532 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002533
Felix Held9cf1dd22018-07-31 14:52:40 +02002534 // execute command queue
2535 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2536
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002537 wait_428c(channel);
2538 }
2539
2540 /* XXX: check any measured value ? */
2541
2542 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002543 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2544 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2545 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002546 }
2547
2548 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002549 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002550 }
2551
2552 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002553 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002554 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2555
2556 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2557 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002558 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002559 if (err)
2560 return err;
2561 }
2562
Felix Held2bb3cdf2018-07-28 00:23:59 +02002563 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002564 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2565
2566 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2567 err = discover_edges_real(ctrl, channel, slotrank,
2568 rising_edges[channel][slotrank]);
2569 if (err)
2570 return err;
2571 }
2572
Felix Held2bb3cdf2018-07-28 00:23:59 +02002573 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002574
2575 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2576 ctrl->timings[channel][slotrank].lanes[lane].falling =
2577 falling_edges[channel][slotrank][lane];
2578 ctrl->timings[channel][slotrank].lanes[lane].rising =
2579 rising_edges[channel][slotrank][lane];
2580 }
2581
2582 FOR_ALL_POPULATED_CHANNELS {
2583 program_timings(ctrl, channel);
2584 }
2585
2586 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002587 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002588 }
2589 return 0;
2590}
2591
2592static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2593 int slotrank, int *edges)
2594{
2595 int edge;
2596 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2597 int statistics[MAX_EDGE_TIMING + 1];
2598 const int reg3000b24[] = { 0, 0xc, 0x2c };
2599 int lane, i;
2600 int lower[NUM_LANES];
2601 int upper[NUM_LANES];
2602 int pat;
2603
2604 FOR_ALL_LANES {
2605 lower[lane] = 0;
2606 upper[lane] = MAX_EDGE_TIMING;
2607 }
2608
2609 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002610 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002611 printram("[%x] = 0x%08x\n",
2612 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2613 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2614 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002615 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002616 printram("using pattern %d\n", pat);
2617 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2618 FOR_ALL_LANES {
2619 ctrl->timings[channel][slotrank].lanes[lane].
2620 rising = edge;
2621 ctrl->timings[channel][slotrank].lanes[lane].
2622 falling = edge;
2623 }
2624 program_timings(ctrl, channel);
2625
2626 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002627 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002628 MCHBAR32(0x4340 + 0x400 * channel +
2629 4 * lane) = 0;
2630 tmp = MCHBAR32(0x400 * channel +
2631 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002632 }
2633 wait_428c(channel);
2634
2635 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002636 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2637 MCHBAR32(0x4230 + 0x400 * channel) =
2638 0x4 | (ctrl->tRCD << 16) |
2639 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
2640 << 10);
2641 MCHBAR32(0x4200 + 0x400 * channel) =
2642 (slotrank << 24) | 0x60000;
2643 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002644
2645 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002646 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2647 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2648 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2649 MCHBAR32(0x4204 + 0x400 * channel) =
2650 slotrank << 24;
2651 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002652
2653 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002654 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2655 MCHBAR32(0x4238 + 0x400 * channel) =
2656 0x4005020 | (max(ctrl->tRTP, 8) << 16);
2657 MCHBAR32(0x4208 + 0x400 * channel) =
2658 slotrank << 24;
2659 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002660
2661 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002662 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2663 MCHBAR32(0x423c + 0x400 * channel) =
2664 0xc01 | (ctrl->tRP << 16);
2665 MCHBAR32(0x420c + 0x400 * channel) =
2666 (slotrank << 24) | 0x60400;
2667 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002668
Felix Held9cf1dd22018-07-31 14:52:40 +02002669 // execute command queue
2670 MCHBAR32(0x4284 + 0x400 * channel) =
2671 RUN_QUEUE_4284(4);
2672
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002673 wait_428c(channel);
2674 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002675 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002676 tmp = MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002677 0x400 * channel + lane * 4);
2678 }
2679
2680 raw_statistics[edge] =
2681 MCHBAR32(0x436c + 0x400 * channel);
2682 }
2683 FOR_ALL_LANES {
2684 struct run rn;
2685 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2686 statistics[edge] =
2687 ! !(raw_statistics[edge] & (1 << lane));
2688 rn = get_longest_zero_run(statistics,
2689 MAX_EDGE_TIMING + 1);
2690 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2691 channel, slotrank, i, rn.start, rn.middle,
2692 rn.end, rn.start + ctrl->edge_offset[i],
2693 rn.end - ctrl->edge_offset[i]);
2694 lower[lane] =
2695 max(rn.start + ctrl->edge_offset[i], lower[lane]);
2696 upper[lane] =
2697 min(rn.end - ctrl->edge_offset[i], upper[lane]);
2698 edges[lane] = (lower[lane] + upper[lane]) / 2;
2699 if (rn.all || (lower[lane] > upper[lane])) {
2700 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2701 channel, slotrank, lane);
2702 return MAKE_ERR;
2703 }
2704 }
2705 }
2706 }
2707
Felix Held2bb3cdf2018-07-28 00:23:59 +02002708 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002709 printram("CPA\n");
2710 return 0;
2711}
2712
2713int discover_edges_write(ramctr_timing *ctrl)
2714{
2715 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2716 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2717 int channel, slotrank, lane;
2718 int err;
2719
2720 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002721 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002722 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2723
2724 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2725 err = discover_edges_write_real(ctrl, channel, slotrank,
2726 falling_edges[channel][slotrank]);
2727 if (err)
2728 return err;
2729 }
2730
Felix Held2bb3cdf2018-07-28 00:23:59 +02002731 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002732 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2733
2734 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2735 err = discover_edges_write_real(ctrl, channel, slotrank,
2736 rising_edges[channel][slotrank]);
2737 if (err)
2738 return err;
2739 }
2740
Felix Held2bb3cdf2018-07-28 00:23:59 +02002741 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002742
2743 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2744 ctrl->timings[channel][slotrank].lanes[lane].falling =
2745 falling_edges[channel][slotrank][lane];
2746 ctrl->timings[channel][slotrank].lanes[lane].rising =
2747 rising_edges[channel][slotrank][lane];
2748 }
2749
2750 FOR_ALL_POPULATED_CHANNELS
2751 program_timings(ctrl, channel);
2752
2753 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002754 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002755 }
2756 return 0;
2757}
2758
2759static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2760{
2761 wait_428c(channel);
2762 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002763 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2764 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002765 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002766 << 10) | (ctrl->tRCD << 16) | 4;
2767 MCHBAR32(0x4200 + 0x400 * channel) =
2768 (slotrank << 24) | 0x60000;
2769 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002770
2771 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002772 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2773 MCHBAR32(0x4234 + 0x400 * channel) =
2774 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2775 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2776 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002777
2778 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002779 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2780 MCHBAR32(0x4238 + 0x400 * channel) =
2781 0x40011e0 | (max(ctrl->tRTP, 8) << 16);
2782 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2783 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002784
2785 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002786 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2787 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2788 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2789 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002790
Felix Held9cf1dd22018-07-31 14:52:40 +02002791 // execute command queue
2792 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2793
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002794 wait_428c(channel);
2795}
2796
2797int discover_timC_write(ramctr_timing *ctrl)
2798{
2799 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2800 int i, pat;
2801
2802 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2803 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2804 int channel, slotrank, lane;
2805
2806 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2807 lower[channel][slotrank][lane] = 0;
2808 upper[channel][slotrank][lane] = MAX_TIMC;
2809 }
2810
Felix Held2bb3cdf2018-07-28 00:23:59 +02002811 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002812 printram("discover timC write:\n");
2813
2814 for (i = 0; i < 3; i++)
2815 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002816 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2817 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002818 udelay(2);
2819 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2820 FOR_ALL_POPULATED_RANKS {
2821 int timC;
2822 u32 raw_statistics[MAX_TIMC + 1];
2823 int statistics[MAX_TIMC + 1];
2824
2825 /* Make sure rn.start < rn.end */
2826 statistics[MAX_TIMC] = 1;
2827
2828 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002829 MCHBAR32(0x4288 + 0x400 * channel) =
2830 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002831 for (timC = 0; timC < MAX_TIMC; timC++) {
2832 FOR_ALL_LANES
2833 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2834 program_timings(ctrl, channel);
2835
2836 test_timC_write (ctrl, channel, slotrank);
2837
2838 raw_statistics[timC] =
2839 MCHBAR32(0x436c + 0x400 * channel);
2840 }
2841 FOR_ALL_LANES {
2842 struct run rn;
2843 for (timC = 0; timC < MAX_TIMC; timC++)
2844 statistics[timC] =
2845 !!(raw_statistics[timC] &
2846 (1 << lane));
2847
2848 rn = get_longest_zero_run(statistics,
2849 MAX_TIMC + 1);
2850 if (rn.all) {
2851 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2852 channel, slotrank, lane);
2853 return MAKE_ERR;
2854 }
2855 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2856 channel, slotrank, i, rn.start,
2857 rn.middle, rn.end,
2858 rn.start + ctrl->timC_offset[i],
2859 rn.end - ctrl->timC_offset[i]);
2860 lower[channel][slotrank][lane] =
2861 max(rn.start + ctrl->timC_offset[i],
2862 lower[channel][slotrank][lane]);
2863 upper[channel][slotrank][lane] =
2864 min(rn.end - ctrl->timC_offset[i],
2865 upper[channel][slotrank][lane]);
2866
2867 }
2868 }
2869 }
2870 }
2871
2872 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002873 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002874 udelay(2);
2875 }
2876
Felix Held2bb3cdf2018-07-28 00:23:59 +02002877 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002878
2879 printram("CPB\n");
2880
2881 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2882 printram("timC %d, %d, %d: %x\n", channel,
2883 slotrank, lane,
2884 (lower[channel][slotrank][lane] +
2885 upper[channel][slotrank][lane]) / 2);
2886 ctrl->timings[channel][slotrank].lanes[lane].timC =
2887 (lower[channel][slotrank][lane] +
2888 upper[channel][slotrank][lane]) / 2;
2889 }
2890 FOR_ALL_POPULATED_CHANNELS {
2891 program_timings(ctrl, channel);
2892 }
2893 return 0;
2894}
2895
2896void normalize_training(ramctr_timing * ctrl)
2897{
2898 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002899 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002900
2901 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2902 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002903 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002904 FOR_ALL_LANES mat =
2905 max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002906 printram("normalize %d, %d, %d: mat %d\n",
2907 channel, slotrank, lane, mat);
2908
2909 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2910 printram("normalize %d, %d, %d: delta %d\n",
2911 channel, slotrank, lane, delta);
2912
2913 ctrl->timings[channel][slotrank].val_4024 += delta;
2914 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002915 }
2916
2917 FOR_ALL_POPULATED_CHANNELS {
2918 program_timings(ctrl, channel);
2919 }
2920}
2921
2922void write_controller_mr(ramctr_timing * ctrl)
2923{
2924 int channel, slotrank;
2925
2926 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002927 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2928 make_mr0(ctrl, slotrank);
2929 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2930 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002931 }
2932}
2933
2934int channel_test(ramctr_timing *ctrl)
2935{
2936 int channel, slotrank, lane;
2937
2938 slotrank = 0;
2939 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002940 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002941 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2942 channel);
2943 return MAKE_ERR;
2944 }
2945 FOR_ALL_POPULATED_CHANNELS {
2946 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2947
Felix Held2bb3cdf2018-07-28 00:23:59 +02002948 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002949 }
2950
2951 for (slotrank = 0; slotrank < 4; slotrank++)
2952 FOR_ALL_CHANNELS
2953 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2954 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002955 MCHBAR32(0x4f40 + 4 * lane) = 0;
2956 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002957 }
2958 wait_428c(channel);
Felix Held9cf1dd22018-07-31 14:52:40 +02002959
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002960 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002961 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2962 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2963 MCHBAR32(0x4200 + (channel << 10)) =
2964 0x00060000 | (slotrank << 24);
2965 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Felix Held9cf1dd22018-07-31 14:52:40 +02002966
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002967 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002968 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2969 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2970 MCHBAR32(0x4204 + (channel << 10)) =
2971 0x00000000 | (slotrank << 24);
2972 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002973
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002974 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002975 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
2976 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
2977 MCHBAR32(0x4208 + (channel << 10)) =
2978 0x00000000 | (slotrank << 24);
2979 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002980
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002981 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002982 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
2983 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
2984 MCHBAR32(0x420c + (channel << 10)) =
2985 0x00060400 | (slotrank << 24);
2986 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
Felix Held9cf1dd22018-07-31 14:52:40 +02002987
2988 // execute command queue
2989 MCHBAR32(0x4284 + (channel << 10)) = RUN_QUEUE_4284(4);
2990
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002991 wait_428c(channel);
2992 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02002993 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002994 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
2995 channel, slotrank, lane);
2996 return MAKE_ERR;
2997 }
2998 }
2999 return 0;
3000}
3001
3002void set_scrambling_seed(ramctr_timing * ctrl)
3003{
3004 int channel;
3005
3006 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
3007 I don't think so. */
3008 static u32 seeds[NUM_CHANNELS][3] = {
3009 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
3010 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
3011 };
3012 FOR_ALL_POPULATED_CHANNELS {
3013 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02003014 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
3015 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
3016 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003017 }
3018}
3019
3020void set_4f8c(void)
3021{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003022 u32 cpu;
3023
Subrata Banik53b08c32018-12-10 14:11:35 +05303024 cpu = cpu_get_cpuid();
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003025 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3026 MCHBAR32(0x4f8c) = 0x141D1519;
3027 } else {
3028 MCHBAR32(0x4f8c) = 0x551D1519;
3029 }
3030}
3031
3032void prepare_training(ramctr_timing * ctrl)
3033{
3034 int channel;
3035
3036 FOR_ALL_POPULATED_CHANNELS {
3037 // Always drive command bus
Felix Held9fe248f2018-07-31 20:59:45 +02003038 MCHBAR32_OR(0x4004 + 0x400 * channel, 0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003039 }
3040
3041 udelay(1);
3042
3043 FOR_ALL_POPULATED_CHANNELS {
3044 wait_428c(channel);
3045 }
3046}
3047
3048void set_4008c(ramctr_timing * ctrl)
3049{
3050 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003051
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003052 FOR_ALL_POPULATED_CHANNELS {
3053 u32 b20, b4_8_12;
3054 int min_320c = 10000;
3055 int max_320c = -10000;
3056
3057 FOR_ALL_POPULATED_RANKS {
3058 max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c);
3059 min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c);
3060 }
3061
3062 if (max_320c - min_320c > 51)
3063 b20 = 0;
3064 else
3065 b20 = ctrl->ref_card_offset[channel];
3066
3067 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3068 b4_8_12 = 0x3330;
3069 else
3070 b4_8_12 = 0x2220;
3071
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003072 dram_odt_stretch(ctrl, channel);
3073
Felix Held2bb3cdf2018-07-28 00:23:59 +02003074 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003075 0x0a000000 | (b20 << 20) |
3076 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003077 }
3078}
3079
3080void set_42a0(ramctr_timing * ctrl)
3081{
3082 int channel;
3083 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003084 MCHBAR32(0x42a0 + 0x400 * channel) =
3085 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003086 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003087 }
3088}
3089
3090static int encode_5d10(int ns)
3091{
3092 return (ns + 499) / 500;
3093}
3094
3095/* FIXME: values in this function should be hardware revision-dependent. */
3096void final_registers(ramctr_timing * ctrl)
3097{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003098 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3099
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003100 int channel;
3101 int t1_cycles = 0, t1_ns = 0, t2_ns;
3102 int t3_ns;
3103 u32 r32;
3104
Felix Held2bb3cdf2018-07-28 00:23:59 +02003105 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003106
Felix Heldf9b826a2018-07-30 17:56:52 +02003107 FOR_ALL_CHANNELS
3108 MCHBAR32_AND_OR(0x400c + 0x400 * channel, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003109
Patrick Rudolph74203de2017-11-20 11:57:01 +01003110 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003111 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3112 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3113 else
3114 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3115 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3116
Felix Heldf9b826a2018-07-30 17:56:52 +02003117 FOR_ALL_CHANNELS
3118 MCHBAR32(0x4380 + 0x400 * channel) = 0x00000aaa;
3119
Felix Held2bb3cdf2018-07-28 00:23:59 +02003120 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3121 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003122
3123 FOR_ALL_CHANNELS {
3124 switch (ctrl->rankmap[channel]) {
3125 /* Unpopulated channel. */
3126 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003127 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003128 break;
3129 /* Only single-ranked dimms. */
3130 case 1:
3131 case 4:
3132 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003133 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003134 break;
3135 /* Dual-ranked dimms present. */
3136 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003137 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003138 break;
3139 }
3140 }
3141
Felix Held2bb3cdf2018-07-28 00:23:59 +02003142 MCHBAR32(0x5880) = 0xca9171e5;
Felix Held2463aa92018-07-29 21:37:55 +02003143 MCHBAR32_AND_OR(0x5888, ~0xffffff, 0xe4d5d0);
3144 MCHBAR32_AND(0x58a8, ~0x1f);
Felix Heldf9b826a2018-07-30 17:56:52 +02003145
3146 FOR_ALL_CHANNELS
3147 MCHBAR32_AND_OR(0x4294 + 0x400 * channel, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003148
Felix Held9fe248f2018-07-31 20:59:45 +02003149 MCHBAR32_OR(0x5030, 1);
3150 MCHBAR32_OR(0x5030, 0x80);
Felix Held2463aa92018-07-29 21:37:55 +02003151 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003152
3153 /* Find a populated channel. */
3154 FOR_ALL_POPULATED_CHANNELS
3155 break;
3156
Felix Held2bb3cdf2018-07-28 00:23:59 +02003157 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3158 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003159 if (r32 & 0x20000)
3160 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003161 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003162 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3163 if (!(r32 & 0x20000))
3164 t1_ns += 500;
3165
Felix Held2bb3cdf2018-07-28 00:23:59 +02003166 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3167 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003168 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003169 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3170 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003171 }
3172 else
3173 {
3174 t3_ns = 500;
3175 }
3176 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3177 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003178 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3179 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003180 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003181 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003182}
3183
3184void restore_timings(ramctr_timing * ctrl)
3185{
3186 int channel, slotrank, lane;
3187
3188 FOR_ALL_POPULATED_CHANNELS
3189 MCHBAR32(0x4004 + 0x400 * channel) =
3190 ctrl->tRRD
3191 | (ctrl->tRTP << 4)
3192 | (ctrl->tCKE << 8)
3193 | (ctrl->tWTR << 12)
3194 | (ctrl->tFAW << 16)
3195 | (ctrl->tWR << 24)
3196 | (ctrl->cmd_stretch[channel] << 30);
3197
3198 udelay(1);
3199
3200 FOR_ALL_POPULATED_CHANNELS {
3201 wait_428c(channel);
3202 }
3203
3204 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003205 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003206 }
3207
3208 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003209 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003210
3211 FOR_ALL_POPULATED_CHANNELS {
3212 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003213 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003214 }
3215
3216 printram("CPE\n");
3217
Felix Held2bb3cdf2018-07-28 00:23:59 +02003218 MCHBAR32(0x3400) = 0;
3219 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003220
3221 printram("CP5b\n");
3222
3223 FOR_ALL_POPULATED_CHANNELS {
3224 program_timings(ctrl, channel);
3225 }
3226
3227 u32 reg, addr;
3228
3229 while (!(MCHBAR32(0x5084) & 0x10000));
3230 do {
3231 reg = MCHBAR32(0x428c);
3232 } while ((reg & 0x14) == 0);
3233
3234 // Set state of memory controller
3235 MCHBAR32(0x5030) = 0x116;
3236 MCHBAR32(0x4ea0) = 0;
3237
3238 // Wait 500us
3239 udelay(500);
3240
3241 FOR_ALL_CHANNELS {
3242 // Set valid rank CKE
3243 reg = 0;
3244 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3245 addr = 0x400 * channel + 0x42a0;
3246 MCHBAR32(addr) = reg;
3247
3248 // Wait 10ns for ranks to settle
3249 //udelay(0.01);
3250
3251 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3252 MCHBAR32(addr) = reg;
3253
3254 // Write reset using a NOP
3255 write_reset(ctrl);
3256 }
3257
3258 /* mrs commands. */
3259 dram_mrscommands(ctrl);
3260
3261 printram("CP5c\n");
3262
Felix Held2bb3cdf2018-07-28 00:23:59 +02003263 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003264
3265 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003266 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003267 udelay(2);
3268 }
3269
Felix Held2bb3cdf2018-07-28 00:23:59 +02003270 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003271}