blob: a90b055bcecdcc4014fa1bd9927ccbda0e6ebc5b [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>
19#include <console/usb.h>
20#include <string.h>
21#include <arch/io.h>
22#include <cbmem.h>
23#include <arch/cbfs.h>
24#include <cbfs.h>
25#include <northbridge/intel/sandybridge/chip.h>
26#include <device/pci_def.h>
27#include <delay.h>
28#include <arch/cpu.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010029#include "raminit_native.h"
30#include "raminit_common.h"
31#include "sandybridge.h"
32
33/* FIXME: no ECC support. */
34/* FIXME: no support for 3-channel chipsets. */
35
36/*
37 * Register description:
38 * Intel provides a command queue of depth four.
39 * Every command is configured by using multiple registers.
40 * On executing the command queue you have to provide the depth used.
41 *
42 * Known registers:
43 * Channel X = [0, 1]
44 * Command queue index Y = [0, 1, 2, 3]
45 *
46 * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register
47 * Controls the DRAM command signals
48 * Bit 0: !RAS
49 * Bit 1: !CAS
50 * Bit 2: !WE
51 *
52 * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register
53 * Controls the address, bank address and slotrank signals
54 * Bit 0-15 : Address
55 * Bit 20-22: Bank Address
56 * Bit 24-25: slotrank
57 *
58 * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register
59 * Controls the idle time after issuing this DRAM command
60 * Bit 16-32: number of clock-cylces to idle
61 *
62 * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue
63 * Starts to execute all queued commands
64 * Bit 0 : start DRAM command execution
Felix Held9cf1dd22018-07-31 14:52:40 +020065 * Bit 18-19 : number of queued commands - 1
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010066 */
67
Felix Held9cf1dd22018-07-31 14:52:40 +020068#define RUN_QUEUE_4284(x) ((((x) - 1) << 18) | 1) // 0 <= x < 4
69
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010070static void sfence(void)
71{
72 asm volatile ("sfence");
73}
74
75static void toggle_io_reset(void) {
76 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020077 u32 r32 = MCHBAR32(0x5030);
78 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010079 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020080 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010081 udelay(1);
82}
83
84static u32 get_XOVER_CLK(u8 rankmap)
85{
86 return rankmap << 24;
87}
88
89static u32 get_XOVER_CMD(u8 rankmap)
90{
91 u32 reg;
92
93 // enable xover cmd
94 reg = 0x4000;
95
96 // enable xover ctl
97 if (rankmap & 0x3)
98 reg |= 0x20000;
99
100 if (rankmap & 0xc)
101 reg |= 0x4000000;
102
103 return reg;
104}
105
106/* CAS write latency. To be programmed in MR2.
107 * See DDR3 SPEC for MR2 documentation. */
108u8 get_CWL(u32 tCK)
109{
110 /* Get CWL based on tCK using the following rule: */
111 switch (tCK) {
112 case TCK_1333MHZ:
113 return 12;
114 case TCK_1200MHZ:
115 case TCK_1100MHZ:
116 return 11;
117 case TCK_1066MHZ:
118 case TCK_1000MHZ:
119 return 10;
120 case TCK_933MHZ:
121 case TCK_900MHZ:
122 return 9;
123 case TCK_800MHZ:
124 case TCK_700MHZ:
125 return 8;
126 case TCK_666MHZ:
127 return 7;
128 case TCK_533MHZ:
129 return 6;
130 default:
131 return 5;
132 }
133}
134
135void dram_find_common_params(ramctr_timing *ctrl)
136{
137 size_t valid_dimms;
138 int channel, slot;
139 dimm_info *dimms = &ctrl->info;
140
141 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
142 valid_dimms = 0;
143 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
144 const dimm_attr *dimm = &dimms->dimm[channel][slot];
145 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
146 continue;
147 valid_dimms++;
148
149 /* Find all possible CAS combinations */
150 ctrl->cas_supported &= dimm->cas_supported;
151
152 /* Find the smallest common latencies supported by all DIMMs */
153 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
154 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
155 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
156 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
157 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
158 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
159 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
160 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
161 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
162 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
163 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300164 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
165 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100166 }
167
168 if (!ctrl->cas_supported)
169 die("Unsupported DIMM combination. "
170 "DIMMS do not support common CAS latency");
171 if (!valid_dimms)
172 die("No valid DIMMs found");
173}
174
175void dram_xover(ramctr_timing * ctrl)
176{
177 u32 reg;
178 int channel;
179
180 FOR_ALL_CHANNELS {
181 // enable xover clk
182 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
183 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
184 reg);
185 MCHBAR32(channel * 0x100 + 0xc14) = reg;
186
187 // enable xover ctl & xover cmd
188 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
189 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
190 reg);
191 MCHBAR32(0x100 * channel + 0x320c) = reg;
192 }
193}
194
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100195static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100196{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100197 struct cpuid_result cpures;
Iru Cai89af71c2018-08-16 16:46:27 +0800198 u32 addr, cpu, stretch;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100199
200 stretch = ctrl->ref_card_offset[channel];
201 /* ODT stretch: Delay ODT signal by stretch value.
202 * Useful for multi DIMM setups on the same channel. */
203 cpures = cpuid(1);
204 cpu = cpures.eax;
205 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
206 if (stretch == 2)
207 stretch = 3;
Iru Cai89af71c2018-08-16 16:46:27 +0800208 addr = 0x401c + 0x400 * channel;
209 MCHBAR32_AND_OR(addr, 0xffffc3ff,
Felix Held9fe248f2018-07-31 20:59:45 +0200210 (stretch << 12) | (stretch << 10));
Iru Cai89af71c2018-08-16 16:46:27 +0800211 printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr,
212 MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100213 } else {
214 // OTHP
Iru Cai89af71c2018-08-16 16:46:27 +0800215 addr = 0x400c + 0x400 * channel;
216 MCHBAR32_AND_OR(addr, 0xfff0ffff,
Felix Held9fe248f2018-07-31 20:59:45 +0200217 (stretch << 16) | (stretch << 18));
Iru Cai89af71c2018-08-16 16:46:27 +0800218 printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100219 }
220}
221
222void dram_timing_regs(ramctr_timing *ctrl)
223{
224 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100225 int channel;
226
227 FOR_ALL_CHANNELS {
228 // DBP
229 reg = 0;
230 reg |= ctrl->tRCD;
231 reg |= (ctrl->tRP << 4);
232 reg |= (ctrl->CAS << 8);
233 reg |= (ctrl->CWL << 12);
234 reg |= (ctrl->tRAS << 16);
235 printram("DBP [%x] = %x\n", 0x400 * channel + 0x4000, reg);
236 MCHBAR32(0x400 * channel + 0x4000) = reg;
237
238 // RAP
239 reg = 0;
240 reg |= ctrl->tRRD;
241 reg |= (ctrl->tRTP << 4);
242 reg |= (ctrl->tCKE << 8);
243 reg |= (ctrl->tWTR << 12);
244 reg |= (ctrl->tFAW << 16);
245 reg |= (ctrl->tWR << 24);
246 reg |= (3 << 30);
247 printram("RAP [%x] = %x\n", 0x400 * channel + 0x4004, reg);
248 MCHBAR32(0x400 * channel + 0x4004) = reg;
249
250 // OTHP
251 addr = 0x400 * channel + 0x400c;
252 reg = 0;
253 reg |= ctrl->tXPDLL;
254 reg |= (ctrl->tXP << 5);
255 reg |= (ctrl->tAONPD << 8);
256 reg |= 0xa0000;
257 printram("OTHP [%x] = %x\n", addr, reg);
258 MCHBAR32(addr) = reg;
259
260 MCHBAR32(0x400 * channel + 0x4014) = 0;
261
Felix Held9fe248f2018-07-31 20:59:45 +0200262 MCHBAR32_OR(addr, 0x00020000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100263
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100264 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100265
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100266 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200267 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100268 * The tREFIx9 field should be programmed to minimum of
269 * 8.9*tREFI (to allow for possible delays from ZQ or
270 * isoc) and tRASmax (70us) divided by 1024.
271 */
272 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
273
274 reg = ((ctrl->tREFI & 0xffff) << 0) |
275 ((ctrl->tRFC & 0x1ff) << 16) |
276 (((val32 / 1024) & 0x7f) << 25);
277 printram("REFI [%x] = %x\n", 0x400 * channel + 0x4298, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100278 MCHBAR32(0x400 * channel + 0x4298) = reg;
279
Felix Held9fe248f2018-07-31 20:59:45 +0200280 MCHBAR32_OR(0x400 * channel + 0x4294, 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100281
282 // SRFTP
283 reg = 0;
284 val32 = tDLLK;
285 reg = (reg & ~0xfff) | val32;
286 val32 = ctrl->tXSOffset;
287 reg = (reg & ~0xf000) | (val32 << 12);
288 val32 = tDLLK - ctrl->tXSOffset;
289 reg = (reg & ~0x3ff0000) | (val32 << 16);
290 val32 = ctrl->tMOD - 8;
291 reg = (reg & ~0xf0000000) | (val32 << 28);
292 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
293 reg);
294 MCHBAR32(0x400 * channel + 0x42a4) = reg;
295 }
296}
297
298void dram_dimm_mapping(ramctr_timing *ctrl)
299{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100300 int channel;
301 dimm_info *info = &ctrl->info;
302
303 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200304 dimm_attr *dimmA, *dimmB;
305 u32 reg = 0;
306
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100307 if (info->dimm[channel][0].size_mb >=
308 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100309 dimmA = &info->dimm[channel][0];
310 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200311 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100312 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100313 dimmA = &info->dimm[channel][1];
314 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200315 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100316 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100317
Nico Huberac4f2162017-10-01 18:14:43 +0200318 if (dimmA && (dimmA->ranks > 0)) {
319 reg |= dimmA->size_mb / 256;
320 reg |= (dimmA->ranks - 1) << 17;
321 reg |= (dimmA->width / 8 - 1) << 19;
322 }
323
324 if (dimmB && (dimmB->ranks > 0)) {
325 reg |= (dimmB->size_mb / 256) << 8;
326 reg |= (dimmB->ranks - 1) << 18;
327 reg |= (dimmB->width / 8 - 1) << 20;
328 }
329
330 reg |= 1 << 21; /* rank interleave */
331 reg |= 1 << 22; /* enhanced interleave */
332
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100333 if ((dimmA && (dimmA->ranks > 0))
334 || (dimmB && (dimmB->ranks > 0))) {
335 ctrl->mad_dimm[channel] = reg;
336 } else {
337 ctrl->mad_dimm[channel] = 0;
338 }
339 }
340}
341
342void dram_dimm_set_mapping(ramctr_timing * ctrl)
343{
344 int channel;
345 FOR_ALL_CHANNELS {
346 MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
347 }
348}
349
350void dram_zones(ramctr_timing * ctrl, int training)
351{
352 u32 reg, ch0size, ch1size;
353 u8 val;
354 reg = 0;
355 val = 0;
356 if (training) {
357 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
358 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
359 } else {
360 ch0size = ctrl->channel_size_mb[0];
361 ch1size = ctrl->channel_size_mb[1];
362 }
363
364 if (ch0size >= ch1size) {
365 reg = MCHBAR32(0x5014);
366 val = ch1size / 256;
367 reg = (reg & ~0xff000000) | val << 24;
368 reg = (reg & ~0xff0000) | (2 * val) << 16;
369 MCHBAR32(0x5014) = reg;
370 MCHBAR32(0x5000) = 0x24;
371 } else {
372 reg = MCHBAR32(0x5014);
373 val = ch0size / 256;
374 reg = (reg & ~0xff000000) | val << 24;
375 reg = (reg & ~0xff0000) | (2 * val) << 16;
376 MCHBAR32(0x5014) = reg;
377 MCHBAR32(0x5000) = 0x21;
378 }
379}
380
381#define HOST_BRIDGE PCI_DEVFN(0, 0)
382#define DEFAULT_TCK TCK_800MHZ
383
384unsigned int get_mem_min_tck(void)
385{
386 u32 reg32;
387 u8 rev;
388 const struct device *dev;
389 const struct northbridge_intel_sandybridge_config *cfg = NULL;
390
391 dev = dev_find_slot(0, HOST_BRIDGE);
392 if (dev)
393 cfg = dev->chip_info;
394
395 /* If this is zero, it just means devicetree.cb didn't set it */
396 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Patrick Rudolphb794a692017-08-08 13:13:51 +0200397 if (IS_ENABLED(CONFIG_NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
398 return TCK_1333MHZ;
399
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100400 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
401
402 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
403 /* read Capabilities A Register DMFC bits */
404 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
405 reg32 &= 0x7;
406
407 switch (reg32) {
408 case 7: return TCK_533MHZ;
409 case 6: return TCK_666MHZ;
410 case 5: return TCK_800MHZ;
411 /* reserved: */
412 default:
413 break;
414 }
415 } else {
416 /* read Capabilities B Register DMFC bits */
417 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
418 reg32 = (reg32 >> 4) & 0x7;
419
420 switch (reg32) {
421 case 7: return TCK_533MHZ;
422 case 6: return TCK_666MHZ;
423 case 5: return TCK_800MHZ;
424 case 4: return TCK_933MHZ;
425 case 3: return TCK_1066MHZ;
426 case 2: return TCK_1200MHZ;
427 case 1: return TCK_1333MHZ;
428 /* reserved: */
429 default:
430 break;
431 }
432 }
433 return DEFAULT_TCK;
434 } else {
435 if (cfg->max_mem_clock_mhz >= 1066)
436 return TCK_1066MHZ;
437 else if (cfg->max_mem_clock_mhz >= 933)
438 return TCK_933MHZ;
439 else if (cfg->max_mem_clock_mhz >= 800)
440 return TCK_800MHZ;
441 else if (cfg->max_mem_clock_mhz >= 666)
442 return TCK_666MHZ;
443 else if (cfg->max_mem_clock_mhz >= 533)
444 return TCK_533MHZ;
445 else
446 return TCK_400MHZ;
447 }
448}
449
450#define DEFAULT_PCI_MMIO_SIZE 2048
451
452static unsigned int get_mmio_size(void)
453{
454 const struct device *dev;
455 const struct northbridge_intel_sandybridge_config *cfg = NULL;
456
457 dev = dev_find_slot(0, HOST_BRIDGE);
458 if (dev)
459 cfg = dev->chip_info;
460
461 /* If this is zero, it just means devicetree.cb didn't set it */
462 if (!cfg || cfg->pci_mmio_size == 0)
463 return DEFAULT_PCI_MMIO_SIZE;
464 else
465 return cfg->pci_mmio_size;
466}
467
468void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
469{
470 u32 reg, val, reclaim;
471 u32 tom, gfxstolen, gttsize;
472 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
473 tsegbase, mestolenbase;
474 size_t tsegbasedelta, remapbase, remaplimit;
475 uint16_t ggc;
476
477 mmiosize = get_mmio_size();
478
479 ggc = pci_read_config16(NORTHBRIDGE, GGC);
480 if (!(ggc & 2)) {
481 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
482 gttsize = ((ggc >> 8) & 0x3);
483 } else {
484 gfxstolen = 0;
485 gttsize = 0;
486 }
487
488 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
489
490 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
491
492 mestolenbase = tom - me_uma_size;
493
494 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
495 tom - me_uma_size);
496 gfxstolenbase = toludbase - gfxstolen;
497 gttbase = gfxstolenbase - gttsize;
498
499 tsegbase = gttbase - tsegsize;
500
501 // Round tsegbase down to nearest address aligned to tsegsize
502 tsegbasedelta = tsegbase & (tsegsize - 1);
503 tsegbase &= ~(tsegsize - 1);
504
505 gttbase -= tsegbasedelta;
506 gfxstolenbase -= tsegbasedelta;
507 toludbase -= tsegbasedelta;
508
509 // Test if it is possible to reclaim a hole in the RAM addressing
510 if (tom - me_uma_size > toludbase) {
511 // Reclaim is possible
512 reclaim = 1;
513 remapbase = MAX(4096, tom - me_uma_size);
514 remaplimit =
515 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
516 touudbase = remaplimit + 1;
517 } else {
518 // Reclaim not possible
519 reclaim = 0;
520 touudbase = tom - me_uma_size;
521 }
522
523 // Update memory map in pci-e configuration space
524 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
525
526 // TOM (top of memory)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300527 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100528 val = tom & 0xfff;
529 reg = (reg & ~0xfff00000) | (val << 20);
530 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300531 pci_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100532
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300533 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100534 val = tom & 0xfffff000;
535 reg = (reg & ~0x000fffff) | (val >> 12);
536 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300537 pci_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100538
539 // TOLUD (top of low used dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300540 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xbc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100541 val = toludbase & 0xfff;
542 reg = (reg & ~0xfff00000) | (val << 20);
543 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xbc, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300544 pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100545
546 // TOUUD LSB (top of upper usable dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300547 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100548 val = touudbase & 0xfff;
549 reg = (reg & ~0xfff00000) | (val << 20);
550 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300551 pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100552
553 // TOUUD MSB
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300554 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xac);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100555 val = touudbase & 0xfffff000;
556 reg = (reg & ~0x000fffff) | (val >> 12);
557 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xac, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300558 pci_write_config32(PCI_DEV(0, 0, 0), 0xac, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100559
560 if (reclaim) {
561 // REMAP BASE
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300562 pci_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20);
563 pci_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100564
565 // REMAP LIMIT
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300566 pci_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20);
567 pci_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100568 }
569 // TSEG
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300570 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100571 val = tsegbase & 0xfff;
572 reg = (reg & ~0xfff00000) | (val << 20);
573 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300574 pci_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100575
576 // GFX stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300577 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100578 val = gfxstolenbase & 0xfff;
579 reg = (reg & ~0xfff00000) | (val << 20);
580 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300581 pci_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100582
583 // GTT stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300584 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100585 val = gttbase & 0xfff;
586 reg = (reg & ~0xfff00000) | (val << 20);
587 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300588 pci_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100589
590 if (me_uma_size) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300591 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x7c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100592 val = (0x80000 - me_uma_size) & 0xfffff000;
593 reg = (reg & ~0x000fffff) | (val >> 12);
594 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x7c, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300595 pci_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100596
597 // ME base
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300598 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x70);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100599 val = mestolenbase & 0xfff;
600 reg = (reg & ~0xfff00000) | (val << 20);
601 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x70, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300602 pci_write_config32(PCI_DEV(0, 0, 0), 0x70, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100603
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300604 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x74);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100605 val = mestolenbase & 0xfffff000;
606 reg = (reg & ~0x000fffff) | (val >> 12);
607 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x74, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300608 pci_write_config32(PCI_DEV(0, 0, 0), 0x74, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100609
610 // ME mask
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300611 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x78);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100612 val = (0x80000 - me_uma_size) & 0xfff;
613 reg = (reg & ~0xfff00000) | (val << 20);
614 reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem
615
616 reg = (reg & ~0x800) | (1 << 11); // set ME memory enable
617 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x78, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300618 pci_write_config32(PCI_DEV(0, 0, 0), 0x78, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100619 }
620}
621
622static void wait_428c(int channel)
623{
624 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200625 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100626 return;
627 }
628}
629
630static void write_reset(ramctr_timing * ctrl)
631{
632 int channel, slotrank;
633
634 /* choose a populated channel. */
635 channel = (ctrl->rankmap[0]) ? 0 : 1;
636
637 wait_428c(channel);
638
639 /* choose a populated rank. */
640 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
641
642 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200643 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
644 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200645 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200646 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100647
Felix Held9cf1dd22018-07-31 14:52:40 +0200648 // execute command queue - why is bit 22 set here?!
649 MCHBAR32(0x4284 + 0x400 * channel) = (1 << 22) | RUN_QUEUE_4284(1);
650
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100651 wait_428c(channel);
652}
653
654void dram_jedecreset(ramctr_timing * ctrl)
655{
Felix Held9fe248f2018-07-31 20:59:45 +0200656 u32 reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100657 int channel;
658
659 while (!(MCHBAR32(0x5084) & 0x10000));
660 do {
661 reg = MCHBAR32(0x428c);
662 } while ((reg & 0x14) == 0);
663
664 // Set state of memory controller
665 reg = 0x112;
666 MCHBAR32(0x5030) = reg;
667 MCHBAR32(0x4ea0) = 0;
668 reg |= 2; //ddr reset
669 MCHBAR32(0x5030) = reg;
670
671 // Assert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200672 MCHBAR32_AND(0x5030, ~0x2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100673
674 // Wait 200us
675 udelay(200);
676
677 // Deassert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200678 MCHBAR32_OR(0x5030, 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100679
680 // Wait 500us
681 udelay(500);
682
683 // Enable DCLK
Felix Held9fe248f2018-07-31 20:59:45 +0200684 MCHBAR32_OR(0x5030, 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100685
686 // XXX Wait 20ns
687 udelay(1);
688
689 FOR_ALL_CHANNELS {
690 // Set valid rank CKE
Felix Held9fe248f2018-07-31 20:59:45 +0200691 reg = ctrl->rankmap[channel];
692 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100693
694 // Wait 10ns for ranks to settle
695 //udelay(0.01);
696
697 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
Felix Held9fe248f2018-07-31 20:59:45 +0200698 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100699
700 // Write reset using a NOP
701 write_reset(ctrl);
702 }
703}
704
705static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
706{
707 /* Get ODT based on rankmap: */
708 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
709 + ((ctrl->rankmap[channel] >> 2) & 1);
710
711 if (dimms_per_ch == 1) {
712 return (const odtmap){60, 60};
713 } else {
714 return (const odtmap){120, 30};
715 }
716}
717
718static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
719 int reg, u32 val)
720{
721 wait_428c(channel);
722
723 if (ctrl->rank_mirror[channel][slotrank]) {
724 /* DDR3 Rank1 Address mirror
725 * swap the following pins:
726 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
727 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
728 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
729 | ((val & 0xa8) << 1);
730 }
731
732 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200733 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
734 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
735 MCHBAR32(0x4200 + 0x400 * channel) =
736 (slotrank << 24) | (reg << 20) | val | 0x60000;
737 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100738
739 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200740 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
741 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
742 MCHBAR32(0x4204 + 0x400 * channel) =
743 (slotrank << 24) | (reg << 20) | val | 0x60000;
744 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100745
746 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200747 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
748 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
749 MCHBAR32(0x4208 + 0x400 * channel) =
750 (slotrank << 24) | (reg << 20) | val | 0x60000;
751 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200752
753 // execute command queue
754 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100755}
756
757static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
758{
759 u16 mr0reg, mch_cas, mch_wr;
760 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 +0100761 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100762
763 /* DLL Reset - self clearing - set after CLK frequency has been changed */
764 mr0reg = 0x100;
765
766 // Convert CAS to MCH register friendly
767 if (ctrl->CAS < 12) {
768 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
769 } else {
770 mch_cas = (u16) (ctrl->CAS - 12);
771 mch_cas = ((mch_cas << 1) | 0x1);
772 }
773
774 // Convert tWR to MCH register friendly
775 mch_wr = mch_wr_t[ctrl->tWR - 5];
776
777 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
778 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
779 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
780
781 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100782 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100783 return mr0reg;
784}
785
786static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
787{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200788 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100789}
790
791static u32 encode_odt(u32 odt)
792{
793 switch (odt) {
794 case 30:
795 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
796 case 60:
797 return (1 << 2); // RZQ/4
798 case 120:
799 return (1 << 6); // RZQ/2
800 default:
801 case 0:
802 return 0;
803 }
804}
805
806static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
807{
808 odtmap odt;
809 u32 mr1reg;
810
811 odt = get_ODT(ctrl, rank, channel);
812 mr1reg = 0x2;
813
814 mr1reg |= encode_odt(odt.rttnom);
815
816 return mr1reg;
817}
818
819static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
820{
821 u16 mr1reg;
822
823 mr1reg = make_mr1(ctrl, rank, channel);
824
825 write_mrreg(ctrl, channel, rank, 1, mr1reg);
826}
827
828static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
829{
830 u16 pasr, cwl, mr2reg;
831 odtmap odt;
832 int srt;
833
834 pasr = 0;
835 cwl = ctrl->CWL - 5;
836 odt = get_ODT(ctrl, rank, channel);
837
838 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
839
840 mr2reg = 0;
841 mr2reg = (mr2reg & ~0x7) | pasr;
842 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
843 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
844 mr2reg = (mr2reg & ~0x80) | (srt << 7);
845 mr2reg |= (odt.rttwr / 60) << 9;
846
847 write_mrreg(ctrl, channel, rank, 2, mr2reg);
848}
849
850static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
851{
852 write_mrreg(ctrl, channel, rank, 3, 0);
853}
854
855void dram_mrscommands(ramctr_timing * ctrl)
856{
857 u8 slotrank;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100858 int channel;
859
860 FOR_ALL_POPULATED_CHANNELS {
861 FOR_ALL_POPULATED_RANKS {
862 // MR2
863 dram_mr2(ctrl, slotrank, channel);
864
865 // MR3
866 dram_mr3(ctrl, slotrank, channel);
867
868 // MR1
869 dram_mr1(ctrl, slotrank, channel);
870
871 // MR0
872 dram_mr0(ctrl, slotrank, channel);
873 }
874 }
875
876 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200877 MCHBAR32(0x4e20) = 0x7;
878 MCHBAR32(0x4e30) = 0xf1001;
879 MCHBAR32(0x4e00) = 0x60002;
880 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100881
882 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200883 MCHBAR32(0x4e24) = 0x1f003;
884 MCHBAR32(0x4e34) = 0x1901001;
885 MCHBAR32(0x4e04) = 0x60400;
886 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100887
Felix Held9cf1dd22018-07-31 14:52:40 +0200888 // execute command queue on all channels? Why isn't bit 0 set here?
Felix Held2bb3cdf2018-07-28 00:23:59 +0200889 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100890
891 // Drain
892 FOR_ALL_CHANNELS {
893 // Wait for ref drained
894 wait_428c(channel);
895 }
896
897 // Refresh enable
Felix Held9fe248f2018-07-31 20:59:45 +0200898 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100899
900 FOR_ALL_POPULATED_CHANNELS {
Felix Held9fe248f2018-07-31 20:59:45 +0200901 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100902
903 wait_428c(channel);
904
905 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
906
907 // Drain
908 wait_428c(channel);
909
910 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200911 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
912 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
913 MCHBAR32(0x4200 + 0x400 * channel) =
914 (slotrank << 24) | 0x60000;
915 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200916
917 // execute command queue
918 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100919
920 // Drain
921 wait_428c(channel);
922 }
923}
924
925static const u32 lane_registers[] = {
926 0x0000, 0x0200, 0x0400, 0x0600,
927 0x1000, 0x1200, 0x1400, 0x1600,
928 0x0800
929};
930
931void program_timings(ramctr_timing * ctrl, int channel)
932{
933 u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028;
934 int lane;
935 int slotrank, slot;
936 int full_shift = 0;
937 u16 slot320c[NUM_SLOTS];
938
939 FOR_ALL_POPULATED_RANKS {
940 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
941 full_shift = -ctrl->timings[channel][slotrank].val_320c;
942 }
943
944 for (slot = 0; slot < NUM_SLOTS; slot++)
945 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
946 case 0:
947 default:
948 slot320c[slot] = 0x7f;
949 break;
950 case 1:
951 slot320c[slot] =
952 ctrl->timings[channel][2 * slot + 0].val_320c +
953 full_shift;
954 break;
955 case 2:
956 slot320c[slot] =
957 ctrl->timings[channel][2 * slot + 1].val_320c +
958 full_shift;
959 break;
960 case 3:
961 slot320c[slot] =
962 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200963 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100964 full_shift;
965 break;
966 }
967
968 /* enable CMD XOVER */
969 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
970 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
971 reg32 |= (slot320c[1] & 0x7f) << 18;
972 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
973
974 MCHBAR32(0x320c + 0x100 * channel) = reg32;
975
976 /* enable CLK XOVER */
977 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
978 reg_c18 = 0;
979
980 FOR_ALL_POPULATED_RANKS {
981 int shift =
982 ctrl->timings[channel][slotrank].val_320c + full_shift;
983 int offset_val_c14;
984 if (shift < 0)
985 shift = 0;
986 offset_val_c14 = ctrl->reg_c14_offset + shift;
987 /* set CLK phase shift */
988 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
989 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
990 }
991
992 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
993 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
994
995 reg_4028 = MCHBAR32(0x4028 + 0x400 * channel);
996 reg_4028 &= 0xffff0000;
997
998 reg_4024 = 0;
999
1000 FOR_ALL_POPULATED_RANKS {
1001 int post_timA_min_high = 7, post_timA_max_high = 0;
1002 int pre_timA_min_high = 7, pre_timA_max_high = 0;
1003 int shift_402x = 0;
1004 int shift =
1005 ctrl->timings[channel][slotrank].val_320c + full_shift;
1006
1007 if (shift < 0)
1008 shift = 0;
1009
1010 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001011 post_timA_min_high = MIN(post_timA_min_high,
1012 (ctrl->timings[channel][slotrank].lanes[lane].
1013 timA + shift) >> 6);
1014 pre_timA_min_high = MIN(pre_timA_min_high,
1015 ctrl->timings[channel][slotrank].lanes[lane].
1016 timA >> 6);
1017 post_timA_max_high = MAX(post_timA_max_high,
1018 (ctrl->timings[channel][slotrank].lanes[lane].
1019 timA + shift) >> 6);
1020 pre_timA_max_high = MAX(pre_timA_max_high,
1021 ctrl->timings[channel][slotrank].lanes[lane].
1022 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001023 }
1024
1025 if (pre_timA_max_high - pre_timA_min_high <
1026 post_timA_max_high - post_timA_min_high)
1027 shift_402x = +1;
1028 else if (pre_timA_max_high - pre_timA_min_high >
1029 post_timA_max_high - post_timA_min_high)
1030 shift_402x = -1;
1031
1032 reg_4028 |=
1033 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1034 post_timA_min_high) << (4 * slotrank);
1035 reg_4024 |=
1036 (ctrl->timings[channel][slotrank].val_4024 +
1037 shift_402x) << (8 * slotrank);
1038
1039 FOR_ALL_LANES {
1040 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1041 4 * slotrank)
1042 =
1043 (((ctrl->timings[channel][slotrank].lanes[lane].
1044 timA + shift) & 0x3f)
1045 |
1046 ((ctrl->timings[channel][slotrank].lanes[lane].
1047 rising + shift) << 8)
1048 |
1049 (((ctrl->timings[channel][slotrank].lanes[lane].
1050 timA + shift -
1051 (post_timA_min_high << 6)) & 0x1c0) << 10)
1052 | ((ctrl->timings[channel][slotrank].lanes[lane].
1053 falling + shift) << 20));
1054
1055 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1056 4 * slotrank)
1057 =
1058 (((ctrl->timings[channel][slotrank].lanes[lane].
1059 timC + shift) & 0x3f)
1060 |
1061 (((ctrl->timings[channel][slotrank].lanes[lane].
1062 timB + shift) & 0x3f) << 8)
1063 |
1064 (((ctrl->timings[channel][slotrank].lanes[lane].
1065 timB + shift) & 0x1c0) << 9)
1066 |
1067 (((ctrl->timings[channel][slotrank].lanes[lane].
1068 timC + shift) & 0x40) << 13));
1069 }
1070 }
1071 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
1072 MCHBAR32(0x4028 + 0x400 * channel) = reg_4028;
1073}
1074
1075static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1076{
1077 wait_428c(channel);
1078
1079 /* DRAM command MRS
1080 * write MR3 MPR enable
1081 * in this mode only RD and RDA are allowed
1082 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001083 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1084 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1085 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1086 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001087
1088 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001089 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1090 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1091 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1092 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001093
1094 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001095 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1096 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1097 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1098 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001099
1100 /* DRAM command MRS
1101 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001102 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1103 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1104 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1105 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001106
Felix Held9cf1dd22018-07-31 14:52:40 +02001107 // execute command queue
1108 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001109
1110 wait_428c(channel);
1111}
1112
1113static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1114 int lane)
1115{
1116 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001117 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001118 ((timA / 32) & 1) * 4)
1119 >> (timA % 32)) & 1);
1120}
1121
1122struct run {
1123 int middle;
1124 int end;
1125 int start;
1126 int all;
1127 int length;
1128};
1129
1130static struct run get_longest_zero_run(int *seq, int sz)
1131{
1132 int i, ls;
1133 int bl = 0, bs = 0;
1134 struct run ret;
1135
1136 ls = 0;
1137 for (i = 0; i < 2 * sz; i++)
1138 if (seq[i % sz]) {
1139 if (i - ls > bl) {
1140 bl = i - ls;
1141 bs = ls;
1142 }
1143 ls = i + 1;
1144 }
1145 if (bl == 0) {
1146 ret.middle = sz / 2;
1147 ret.start = 0;
1148 ret.end = sz;
1149 ret.all = 1;
1150 return ret;
1151 }
1152
1153 ret.start = bs % sz;
1154 ret.end = (bs + bl - 1) % sz;
1155 ret.middle = (bs + (bl - 1) / 2) % sz;
1156 ret.length = bl;
1157 ret.all = 0;
1158
1159 return ret;
1160}
1161
1162static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1163 int slotrank, int *upperA)
1164{
1165 int timA;
1166 int statistics[NUM_LANES][128];
1167 int lane;
1168
1169 for (timA = 0; timA < 128; timA++) {
1170 FOR_ALL_LANES {
1171 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1172 }
1173 program_timings(ctrl, channel);
1174
1175 test_timA(ctrl, channel, slotrank);
1176
1177 FOR_ALL_LANES {
1178 statistics[lane][timA] =
1179 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001180 }
1181 }
1182 FOR_ALL_LANES {
1183 struct run rn = get_longest_zero_run(statistics[lane], 128);
1184 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1185 upperA[lane] = rn.end;
1186 if (upperA[lane] < rn.middle)
1187 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001188 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001189 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001190 }
1191}
1192
1193static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1194 int *upperA)
1195{
1196 int timA_delta;
1197 int statistics[NUM_LANES][51];
1198 int lane, i;
1199
1200 memset(statistics, 0, sizeof(statistics));
1201
1202 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1203 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1204 timA = upperA[lane] + timA_delta + 0x40;
1205 program_timings(ctrl, channel);
1206
1207 for (i = 0; i < 100; i++) {
1208 test_timA(ctrl, channel, slotrank);
1209 FOR_ALL_LANES {
1210 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001211 does_lane_work(ctrl, channel, slotrank,
1212 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001213 }
1214 }
1215 }
1216 FOR_ALL_LANES {
1217 int last_zero, first_all;
1218
1219 for (last_zero = -25; last_zero <= 25; last_zero++)
1220 if (statistics[lane][last_zero + 25])
1221 break;
1222 last_zero--;
1223 for (first_all = -25; first_all <= 25; first_all++)
1224 if (statistics[lane][first_all + 25] == 100)
1225 break;
1226
1227 printram("lane %d: %d, %d\n", lane, last_zero,
1228 first_all);
1229
1230 ctrl->timings[channel][slotrank].lanes[lane].timA =
1231 (last_zero + first_all) / 2 + upperA[lane];
1232 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1233 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1234 }
1235}
1236
1237static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1238 int *upperA)
1239{
1240 int works[NUM_LANES];
1241 int lane;
1242 while (1) {
1243 int all_works = 1, some_works = 0;
1244 program_timings(ctrl, channel);
1245 test_timA(ctrl, channel, slotrank);
1246 FOR_ALL_LANES {
1247 works[lane] =
1248 !does_lane_work(ctrl, channel, slotrank, lane);
1249 if (works[lane])
1250 some_works = 1;
1251 else
1252 all_works = 0;
1253 }
1254 if (all_works)
1255 return 0;
1256 if (!some_works) {
1257 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1258 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1259 channel, slotrank);
1260 return MAKE_ERR;
1261 }
1262 ctrl->timings[channel][slotrank].val_4024 -= 2;
1263 printram("4024 -= 2;\n");
1264 continue;
1265 }
1266 ctrl->timings[channel][slotrank].val_4028 += 2;
1267 printram("4028 += 2;\n");
1268 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1269 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1270 channel, slotrank);
1271 return MAKE_ERR;
1272 }
1273 FOR_ALL_LANES if (works[lane]) {
1274 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1275 128;
1276 upperA[lane] += 128;
1277 printram("increment %d, %d, %d\n", channel,
1278 slotrank, lane);
1279 }
1280 }
1281 return 0;
1282}
1283
1284struct timA_minmax {
1285 int timA_min_high, timA_max_high;
1286};
1287
1288static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1289 struct timA_minmax *mnmx)
1290{
1291 int lane;
1292 mnmx->timA_min_high = 7;
1293 mnmx->timA_max_high = 0;
1294
1295 FOR_ALL_LANES {
1296 if (mnmx->timA_min_high >
1297 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1298 mnmx->timA_min_high =
1299 (ctrl->timings[channel][slotrank].lanes[lane].
1300 timA >> 6);
1301 if (mnmx->timA_max_high <
1302 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1303 mnmx->timA_max_high =
1304 (ctrl->timings[channel][slotrank].lanes[lane].
1305 timA >> 6);
1306 }
1307}
1308
1309static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1310 struct timA_minmax *mnmx)
1311{
1312 struct timA_minmax post;
1313 int shift_402x = 0;
1314
1315 /* Get changed maxima. */
1316 pre_timA_change(ctrl, channel, slotrank, &post);
1317
1318 if (mnmx->timA_max_high - mnmx->timA_min_high <
1319 post.timA_max_high - post.timA_min_high)
1320 shift_402x = +1;
1321 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1322 post.timA_max_high - post.timA_min_high)
1323 shift_402x = -1;
1324 else
1325 shift_402x = 0;
1326
1327 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1328 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1329 printram("4024 += %d;\n", shift_402x);
1330 printram("4028 += %d;\n", shift_402x);
1331}
1332
1333/* Compensate the skew between DQS and DQs.
1334 * To ease PCB design a small skew between Data Strobe signals and
1335 * Data Signals is allowed.
1336 * The controller has to measure and compensate this skew for every byte-lane.
1337 * By delaying either all DQs signals or DQS signal, a full phase
1338 * shift can be introduced.
1339 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1340 *
1341 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1342 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1343 * The memory controller iterates over all possible values to do a full phase shift
1344 * and issues read commands.
1345 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1346 * 0xFF 0x00 0xFF ...
1347 * Once the controller has detected this pattern a bit in the result register is
1348 * set for the current phase shift.
1349 */
1350int read_training(ramctr_timing * ctrl)
1351{
1352 int channel, slotrank, lane;
1353 int err;
1354
1355 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1356 int all_high, some_high;
1357 int upperA[NUM_LANES];
1358 struct timA_minmax mnmx;
1359
Felix Held2bb3cdf2018-07-28 00:23:59 +02001360 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001361
Felix Held2bb3cdf2018-07-28 00:23:59 +02001362 /* DRAM command PREA */
1363 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1364 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1365 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1366 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001367
1368 // execute command queue
1369 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001370
Felix Held2bb3cdf2018-07-28 00:23:59 +02001371 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001372
Felix Held2bb3cdf2018-07-28 00:23:59 +02001373 ctrl->timings[channel][slotrank].val_4028 = 4;
1374 ctrl->timings[channel][slotrank].val_4024 = 55;
1375 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001376
Felix Held2bb3cdf2018-07-28 00:23:59 +02001377 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001378
Felix Held2bb3cdf2018-07-28 00:23:59 +02001379 all_high = 1;
1380 some_high = 0;
1381 FOR_ALL_LANES {
1382 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1383 0x40)
1384 some_high = 1;
1385 else
1386 all_high = 0;
1387 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001388
1389 if (all_high) {
1390 ctrl->timings[channel][slotrank].val_4028--;
1391 printram("4028--;\n");
1392 FOR_ALL_LANES {
1393 ctrl->timings[channel][slotrank].lanes[lane].
1394 timA -= 0x40;
1395 upperA[lane] -= 0x40;
1396
1397 }
1398 } else if (some_high) {
1399 ctrl->timings[channel][slotrank].val_4024++;
1400 ctrl->timings[channel][slotrank].val_4028++;
1401 printram("4024++;\n");
1402 printram("4028++;\n");
1403 }
1404
1405 program_timings(ctrl, channel);
1406
1407 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1408
1409 err = discover_402x(ctrl, channel, slotrank, upperA);
1410 if (err)
1411 return err;
1412
1413 post_timA_change(ctrl, channel, slotrank, &mnmx);
1414 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1415
1416 discover_timA_fine(ctrl, channel, slotrank, upperA);
1417
1418 post_timA_change(ctrl, channel, slotrank, &mnmx);
1419 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1420
1421 FOR_ALL_LANES {
1422 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1423 }
1424 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1425 printram("4028 -= %d;\n", mnmx.timA_min_high);
1426
1427 post_timA_change(ctrl, channel, slotrank, &mnmx);
1428
1429 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1430 ctrl->timings[channel][slotrank].val_4024,
1431 ctrl->timings[channel][slotrank].val_4028);
1432
1433 printram("final results:\n");
1434 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001435 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1436 lane,
1437 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001438
Felix Held2bb3cdf2018-07-28 00:23:59 +02001439 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001440
1441 toggle_io_reset();
1442 }
1443
1444 FOR_ALL_POPULATED_CHANNELS {
1445 program_timings(ctrl, channel);
1446 }
1447 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001448 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001449 }
1450 return 0;
1451}
1452
1453static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1454{
1455 int lane;
1456
1457 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001458 volatile u32 tmp;
1459 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
1460 tmp = MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001461 }
1462
1463 wait_428c(channel);
1464
1465 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001466 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1467 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001468 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001469 | 4 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001470 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001471 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001472
1473 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001474 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1475 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1476 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1477 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001478
1479 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001480 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1481 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1482 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1483 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001484
1485 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001486 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1487 MCHBAR32(0x423c + 0x400 * channel) =
1488 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1489 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1490 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001491
Felix Held9cf1dd22018-07-31 14:52:40 +02001492 // execute command queue
1493 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001494
1495 wait_428c(channel);
1496
1497 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001498 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1499 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1500 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1501 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001502
1503 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001504 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1505 MCHBAR32(0x4234 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001506 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001507 | 8 | (ctrl->CAS << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001508 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001509 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001510
1511 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001512 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1513 MCHBAR32(0x4238 + 0x400 * channel) =
1514 0x40011f4 | (max(ctrl->tRTP, 8) << 16);
1515 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1516 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001517
1518 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001519 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1520 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1521 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1522 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001523
1524 // execute command queue
1525 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1526
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001527 wait_428c(channel);
1528}
1529
1530static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1531{
1532 int timC;
1533 int statistics[NUM_LANES][MAX_TIMC + 1];
1534 int lane;
1535
1536 wait_428c(channel);
1537
1538 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001539 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1540 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
Felix Held9fe248f2018-07-31 20:59:45 +02001541 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001542 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001543
1544 // execute command queue
1545 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001546
1547 for (timC = 0; timC <= MAX_TIMC; timC++) {
1548 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1549 timC = timC;
1550 program_timings(ctrl, channel);
1551
1552 test_timC(ctrl, channel, slotrank);
1553
1554 FOR_ALL_LANES {
1555 statistics[lane][timC] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001556 MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001557 }
1558 }
1559 FOR_ALL_LANES {
1560 struct run rn =
1561 get_longest_zero_run(statistics[lane], MAX_TIMC + 1);
1562 ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
1563 if (rn.all) {
1564 printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
1565 channel, slotrank, lane);
1566 return MAKE_ERR;
1567 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001568 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001569 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001570 }
1571 return 0;
1572}
1573
1574static int get_precedening_channels(ramctr_timing * ctrl, int target_channel)
1575{
1576 int channel, ret = 0;
1577 FOR_ALL_POPULATED_CHANNELS if (channel < target_channel)
1578 ret++;
1579 return ret;
1580}
1581
1582static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b)
1583{
1584 unsigned j;
1585 unsigned channel_offset =
1586 get_precedening_channels(ctrl, channel) * 0x40;
1587 for (j = 0; j < 16; j++)
1588 write32((void *)(0x04000000 + channel_offset + 4 * j), j & 2 ? b : a);
1589 sfence();
1590}
1591
1592static int num_of_channels(const ramctr_timing * ctrl)
1593{
1594 int ret = 0;
1595 int channel;
1596 FOR_ALL_POPULATED_CHANNELS ret++;
1597 return ret;
1598}
1599
1600static void fill_pattern1(ramctr_timing * ctrl, int channel)
1601{
1602 unsigned j;
1603 unsigned channel_offset =
1604 get_precedening_channels(ctrl, channel) * 0x40;
1605 unsigned channel_step = 0x40 * num_of_channels(ctrl);
1606 for (j = 0; j < 16; j++)
1607 write32((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff);
1608 for (j = 0; j < 16; j++)
1609 write32((void *)(0x04000000 + channel_offset + channel_step + j * 4), 0);
1610 sfence();
1611}
1612
1613static void precharge(ramctr_timing * ctrl)
1614{
1615 int channel, slotrank, lane;
1616
1617 FOR_ALL_POPULATED_CHANNELS {
1618 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1619 ctrl->timings[channel][slotrank].lanes[lane].falling =
1620 16;
1621 ctrl->timings[channel][slotrank].lanes[lane].rising =
1622 16;
1623 }
1624
1625 program_timings(ctrl, channel);
1626
1627 FOR_ALL_POPULATED_RANKS {
1628 wait_428c(channel);
1629
1630 /* DRAM command MRS
1631 * write MR3 MPR enable
1632 * in this mode only RD and RDA are allowed
1633 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001634 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1635 MCHBAR32(0x4230 + 0x400 * channel) =
1636 0xc01 | (ctrl->tMOD << 16);
1637 MCHBAR32(0x4200 + 0x400 * channel) =
1638 (slotrank << 24) | 0x360004;
1639 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001640
1641 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001642 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1643 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1644 MCHBAR32(0x4204 + 0x400 * channel) =
1645 (slotrank << 24) | 0;
1646 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001647
1648 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001649 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1650 MCHBAR32(0x4238 + 0x400 * channel) =
1651 0x1001 | ((ctrl->CAS + 8) << 16);
1652 MCHBAR32(0x4208 + 0x400 * channel) =
1653 (slotrank << 24) | 0x60000;
1654 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001655
1656 /* DRAM command MRS
1657 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001658 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1659 MCHBAR32(0x423c + 0x400 * channel) =
1660 0xc01 | (ctrl->tMOD << 16);
1661 MCHBAR32(0x420c + 0x400 * channel) =
1662 (slotrank << 24) | 0x360000;
1663 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001664
1665 // execute command queue
1666 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001667
1668 wait_428c(channel);
1669 }
1670
1671 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1672 ctrl->timings[channel][slotrank].lanes[lane].falling =
1673 48;
1674 ctrl->timings[channel][slotrank].lanes[lane].rising =
1675 48;
1676 }
1677
1678 program_timings(ctrl, channel);
1679
1680 FOR_ALL_POPULATED_RANKS {
1681 wait_428c(channel);
1682 /* DRAM command MRS
1683 * write MR3 MPR enable
1684 * in this mode only RD and RDA are allowed
1685 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001686 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1687 MCHBAR32(0x4230 + 0x400 * channel) =
1688 0xc01 | (ctrl->tMOD << 16);
1689 MCHBAR32(0x4200 + 0x400 * channel) =
1690 (slotrank << 24) | 0x360004;
1691 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001692
1693 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001694 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1695 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1696 MCHBAR32(0x4204 + 0x400 * channel) =
1697 (slotrank << 24) | 0;
1698 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001699
1700 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001701 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1702 MCHBAR32(0x4238 + 0x400 * channel) =
1703 0x1001 | ((ctrl->CAS + 8) << 16);
1704 MCHBAR32(0x4208 + 0x400 * channel) =
1705 (slotrank << 24) | 0x60000;
1706 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001707
1708 /* DRAM command MRS
1709 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001710 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1711 MCHBAR32(0x423c + 0x400 * channel) =
1712 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001713 MCHBAR32(0x420c + 0x400 * channel) =
1714 (slotrank << 24) | 0x360000;
1715 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001716
Felix Held9cf1dd22018-07-31 14:52:40 +02001717 // execute command queue
1718 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1719
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001720 wait_428c(channel);
1721 }
1722 }
1723}
1724
1725static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1726{
1727 /* enable DQs on this slotrank */
1728 write_mrreg(ctrl, channel, slotrank, 1,
1729 0x80 | make_mr1(ctrl, slotrank, channel));
1730
1731 wait_428c(channel);
1732 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001733 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1734 MCHBAR32(0x4230 + 0x400 * channel) =
1735 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1736 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1737 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001738
1739 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001740 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1741 MCHBAR32(0x4234 + 0x400 * channel) =
1742 0x4000c01 | ((ctrl->CAS + 38) << 16);
1743 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1744 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001745
Felix Held9cf1dd22018-07-31 14:52:40 +02001746 // execute command queue
1747 MCHBAR32(0x400 * channel + 0x4284) = RUN_QUEUE_4284(2);
1748
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001749 wait_428c(channel);
1750
1751 /* disable DQs on this slotrank */
1752 write_mrreg(ctrl, channel, slotrank, 1,
1753 0x1080 | make_mr1(ctrl, slotrank, channel));
1754}
1755
1756static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1757{
1758 int timB;
1759 int statistics[NUM_LANES][128];
1760 int lane;
1761
Felix Held2bb3cdf2018-07-28 00:23:59 +02001762 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001763
1764 for (timB = 0; timB < 128; timB++) {
1765 FOR_ALL_LANES {
1766 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1767 }
1768 program_timings(ctrl, channel);
1769
1770 test_timB(ctrl, channel, slotrank);
1771
1772 FOR_ALL_LANES {
1773 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001774 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001775 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1776 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001777 }
1778 }
1779 FOR_ALL_LANES {
1780 struct run rn = get_longest_zero_run(statistics[lane], 128);
1781 /* timC is a direct function of timB's 6 LSBs.
1782 * Some tests increments the value of timB by a small value,
1783 * which might cause the 6bit value to overflow, if it's close
1784 * to 0x3F. Increment the value by a small offset if it's likely
1785 * to overflow, to make sure it won't overflow while running
1786 * tests and bricks the system due to a non matching timC.
1787 *
1788 * TODO: find out why some tests (edge write discovery)
1789 * increment timB. */
1790 if ((rn.start & 0x3F) == 0x3E)
1791 rn.start += 2;
1792 else if ((rn.start & 0x3F) == 0x3F)
1793 rn.start += 1;
1794 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1795 if (rn.all) {
1796 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1797 channel, slotrank, lane);
1798 return MAKE_ERR;
1799 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001800 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1801 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001802 }
1803 return 0;
1804}
1805
1806static int get_timB_high_adjust(u64 val)
1807{
1808 int i;
1809
1810 /* good */
1811 if (val == 0xffffffffffffffffLL)
1812 return 0;
1813
1814 if (val >= 0xf000000000000000LL) {
1815 /* needs negative adjustment */
1816 for (i = 0; i < 8; i++)
1817 if (val << (8 * (7 - i) + 4))
1818 return -i;
1819 } else {
1820 /* needs positive adjustment */
1821 for (i = 0; i < 8; i++)
1822 if (val >> (8 * (7 - i) + 4))
1823 return i;
1824 }
1825 return 8;
1826}
1827
1828static void adjust_high_timB(ramctr_timing * ctrl)
1829{
1830 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001831 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001832 FOR_ALL_POPULATED_CHANNELS {
1833 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001834 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001835 }
1836 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1837
Felix Held2bb3cdf2018-07-28 00:23:59 +02001838 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001839
1840 wait_428c(channel);
1841
1842 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001843 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1844 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1845 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1846 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001847
1848 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001849 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1850 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1851 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1852 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001853
1854 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001855 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1856 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1857 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1858 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001859
1860 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001861 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1862 MCHBAR32(0x423c + 0x400 * channel) =
1863 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1864 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1865 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001866
Felix Held9cf1dd22018-07-31 14:52:40 +02001867 // execute command queue
1868 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001869
1870 wait_428c(channel);
1871
1872 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001873 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1874 MCHBAR32(0x4230 + 0x400 * channel) =
1875 0xc01 | ((ctrl->tRP) << 16);
1876 MCHBAR32(0x4200 + 0x400 * channel) =
1877 (slotrank << 24) | 0x60400;
1878 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001879
1880 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001881 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1882 MCHBAR32(0x4234 + 0x400 * channel) =
1883 0xc01 | ((ctrl->tRCD) << 16);
1884 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1885 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001886
1887 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001888 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1889 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001890 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001891 ctrl->timings[channel][slotrank].val_4028) << 16);
1892 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1893 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001894
Felix Held9cf1dd22018-07-31 14:52:40 +02001895 // execute command queue
1896 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
1897
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001898 wait_428c(channel);
1899 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001900 u64 res = MCHBAR32(lane_registers[lane] +
1901 0x100 * channel + 4);
1902 res |= ((u64) MCHBAR32(lane_registers[lane] +
1903 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001904 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1905 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1906 get_timB_high_adjust(res) * 64;
1907
1908 printram("High adjust %d:%016llx\n", lane, res);
1909 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1910 slotrank, lane, old,
1911 ctrl->timings[channel][slotrank].lanes[lane].
1912 timB);
1913 }
1914 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001915 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001916}
1917
1918static void write_op(ramctr_timing * ctrl, int channel)
1919{
1920 int slotrank;
1921
1922 wait_428c(channel);
1923
1924 /* choose an existing rank. */
1925 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1926
1927 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001928 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1929 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001930 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001931 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001932
Felix Held9cf1dd22018-07-31 14:52:40 +02001933 // execute command queue
1934 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
1935
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001936 wait_428c(channel);
1937}
1938
1939/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1940 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1941 * the chips at different times with respect to command, address and
1942 * clock signals.
1943 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1944 * shift can be introduced.
1945 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1946 *
1947 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1948 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1949 * sampled value on the data lanes (DQs).
1950 */
1951int write_training(ramctr_timing * ctrl)
1952{
1953 int channel, slotrank, lane;
1954 int err;
1955
1956 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001957 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001958
1959 FOR_ALL_POPULATED_CHANNELS {
1960 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001961 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001962 }
1963
1964 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001965 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001966 FOR_ALL_POPULATED_CHANNELS {
1967 write_op(ctrl, channel);
1968 }
1969
1970 /* enable write leveling on all ranks
1971 * disable all DQ outputs
1972 * only NOP is allowed in this mode */
1973 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02001974 FOR_ALL_POPULATED_RANKS
1975 write_mrreg(ctrl, channel, slotrank, 1,
1976 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001977
Felix Held2bb3cdf2018-07-28 00:23:59 +02001978 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001979
1980 toggle_io_reset();
1981
1982 /* set any valid value for timB, it gets corrected later */
1983 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1984 err = discover_timB(ctrl, channel, slotrank);
1985 if (err)
1986 return err;
1987 }
1988
1989 /* disable write leveling on all ranks */
1990 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
1991 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02001992 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001993
Felix Held2bb3cdf2018-07-28 00:23:59 +02001994 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001995
1996 FOR_ALL_POPULATED_CHANNELS
1997 wait_428c(channel);
1998
1999 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02002000 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002001
2002 FOR_ALL_POPULATED_CHANNELS {
Felix Heldb802c072018-07-29 21:46:19 +02002003 volatile u32 tmp;
Felix Held2463aa92018-07-29 21:37:55 +02002004 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002005 tmp = MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002006 wait_428c(channel);
2007
2008 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002009 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2010 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2011 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2012 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002013
Felix Held9cf1dd22018-07-31 14:52:40 +02002014 // execute command queue
2015 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2016
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002017 wait_428c(channel);
2018 }
2019
2020 toggle_io_reset();
2021
2022 printram("CPE\n");
2023 precharge(ctrl);
2024 printram("CPF\n");
2025
2026 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002027 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002028 }
2029
2030 FOR_ALL_POPULATED_CHANNELS {
2031 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002032 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002033 }
2034
2035 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2036 err = discover_timC(ctrl, channel, slotrank);
2037 if (err)
2038 return err;
2039 }
2040
2041 FOR_ALL_POPULATED_CHANNELS
2042 program_timings(ctrl, channel);
2043
2044 /* measure and adjust timB timings */
2045 adjust_high_timB(ctrl);
2046
2047 FOR_ALL_POPULATED_CHANNELS
2048 program_timings(ctrl, channel);
2049
2050 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002051 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002052 }
2053 return 0;
2054}
2055
2056static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2057{
2058 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2059 int timC_delta;
2060 int lanes_ok = 0;
2061 int ctr = 0;
2062 int lane;
2063
2064 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2065 FOR_ALL_LANES {
2066 ctrl->timings[channel][slotrank].lanes[lane].timC =
2067 saved_rt.lanes[lane].timC + timC_delta;
2068 }
2069 program_timings(ctrl, channel);
2070 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002071 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002072 }
2073
Felix Held2bb3cdf2018-07-28 00:23:59 +02002074 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002075
2076 wait_428c(channel);
2077 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002078 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2079 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002080 ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002081 | 8 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002082 MCHBAR32(0x4200 + 0x400 * channel) =
2083 (slotrank << 24) | ctr | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002084 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Felix Held9fe248f2018-07-31 20:59:45 +02002085
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002086 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002087 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2088 MCHBAR32(0x4234 + 0x400 * channel) =
2089 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2090 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2091 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2092 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002093
2094 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002095 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2096 MCHBAR32(0x4238 + 0x400 * channel) =
2097 0x4001020 | (max(ctrl->tRTP, 8) << 16);
2098 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2099 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2100 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002101
2102 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002103 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2104 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2105 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2106 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002107
Felix Held9cf1dd22018-07-31 14:52:40 +02002108 // execute command queue
2109 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2110
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002111 wait_428c(channel);
2112 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002113 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002114
2115 if (r32 == 0)
2116 lanes_ok |= 1 << lane;
2117 }
2118 ctr++;
2119 if (lanes_ok == ((1 << NUM_LANES) - 1))
2120 break;
2121 }
2122
2123 ctrl->timings[channel][slotrank] = saved_rt;
2124
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002125 return lanes_ok != ((1 << NUM_LANES) - 1);
2126}
2127
2128#include "raminit_patterns.h"
2129
2130static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2131{
2132 unsigned i, j;
2133 unsigned channel_offset =
2134 get_precedening_channels(ctrl, channel) * 0x40;
2135 unsigned channel_step = 0x40 * num_of_channels(ctrl);
2136
2137 if (patno) {
2138 u8 base8 = 0x80 >> ((patno - 1) % 8);
2139 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2140 for (i = 0; i < 32; i++) {
2141 for (j = 0; j < 16; j++) {
2142 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2143 if (invert[patno - 1][i] & (1 << (j / 2)))
2144 val = ~val;
2145 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2146 j * 4), val);
2147 }
2148 }
2149
2150 } else {
2151 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2152 for (j = 0; j < 16; j++)
2153 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2154 j * 4), pattern[i][j]);
2155 }
2156 sfence();
2157 }
2158}
2159
2160static void reprogram_320c(ramctr_timing * ctrl)
2161{
2162 int channel, slotrank;
2163
2164 FOR_ALL_POPULATED_CHANNELS {
2165 wait_428c(channel);
2166
2167 /* choose an existing rank. */
2168 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2169
2170 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002171 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2172 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002173 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002174 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002175
Felix Held9cf1dd22018-07-31 14:52:40 +02002176 // execute command queue
2177 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2178
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002179 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002180 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002181 }
2182
2183 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002184 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002185 FOR_ALL_POPULATED_CHANNELS {
2186 wait_428c(channel);
2187
2188 /* choose an existing rank. */
2189 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2190
2191 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002192 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2193 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002194 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002195 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002196
Felix Held9cf1dd22018-07-31 14:52:40 +02002197 // execute command queue
2198 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2199
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002200 wait_428c(channel);
2201 }
2202
2203 /* jedec reset */
2204 dram_jedecreset(ctrl);
2205 /* mrs commands. */
2206 dram_mrscommands(ctrl);
2207
2208 toggle_io_reset();
2209}
2210
2211#define MIN_C320C_LEN 13
2212
2213static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2214{
2215 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2216 int slotrank;
2217 int c320c;
2218 int stat[NUM_SLOTRANKS][256];
2219 int delta = 0;
2220
2221 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2222
2223 FOR_ALL_POPULATED_RANKS {
2224 saved_timings[channel][slotrank] =
2225 ctrl->timings[channel][slotrank];
2226 }
2227
2228 ctrl->cmd_stretch[channel] = cmd_stretch;
2229
2230 MCHBAR32(0x4004 + 0x400 * channel) =
2231 ctrl->tRRD
2232 | (ctrl->tRTP << 4)
2233 | (ctrl->tCKE << 8)
2234 | (ctrl->tWTR << 12)
2235 | (ctrl->tFAW << 16)
2236 | (ctrl->tWR << 24)
2237 | (ctrl->cmd_stretch[channel] << 30);
2238
2239 if (ctrl->cmd_stretch[channel] == 2)
2240 delta = 2;
2241 else if (ctrl->cmd_stretch[channel] == 0)
2242 delta = 4;
2243
2244 FOR_ALL_POPULATED_RANKS {
2245 ctrl->timings[channel][slotrank].val_4024 -= delta;
2246 }
2247
2248 for (c320c = -127; c320c <= 127; c320c++) {
2249 FOR_ALL_POPULATED_RANKS {
2250 ctrl->timings[channel][slotrank].val_320c = c320c;
2251 }
2252 program_timings(ctrl, channel);
2253 reprogram_320c(ctrl);
2254 FOR_ALL_POPULATED_RANKS {
2255 stat[slotrank][c320c + 127] =
2256 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002257 }
2258 }
2259 FOR_ALL_POPULATED_RANKS {
2260 struct run rn =
2261 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002262 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002263 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2264 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002265 if (rn.all || rn.length < MIN_C320C_LEN) {
2266 FOR_ALL_POPULATED_RANKS {
2267 ctrl->timings[channel][slotrank] =
2268 saved_timings[channel][slotrank];
2269 }
2270 return MAKE_ERR;
2271 }
2272 }
2273
2274 return 0;
2275}
2276
2277/* Adjust CMD phase shift and try multiple command rates.
2278 * A command rate of 2T doubles the time needed for address and
2279 * command decode. */
2280int command_training(ramctr_timing *ctrl)
2281{
2282 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002283
2284 FOR_ALL_POPULATED_CHANNELS {
2285 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002286 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002287 }
2288
2289 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002290 int cmdrate, err;
2291
2292 /*
2293 * Dual DIMM per channel:
2294 * Issue: While c320c discovery seems to succeed raminit
2295 * will fail in write training.
2296 * Workaround: Skip 1T in dual DIMM mode, that's only
2297 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002298 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2299 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002300 *
2301 * Single DIMM per channel:
2302 * Try command rate 1T and 2T
2303 */
2304 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002305 if (ctrl->tCMD)
2306 /* XMP gives the CMD rate in clock ticks, not ns */
2307 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002308
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002309 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002310 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2311
2312 if (!err)
2313 break;
2314 }
2315
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002316 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002317 printk(BIOS_EMERG, "c320c discovery failed\n");
2318 return err;
2319 }
2320
2321 printram("Using CMD rate %uT on channel %u\n",
2322 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002323 }
2324
2325 FOR_ALL_POPULATED_CHANNELS
2326 program_timings(ctrl, channel);
2327
2328 reprogram_320c(ctrl);
2329 return 0;
2330}
2331
2332
2333static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2334 int *edges)
2335{
2336 int edge;
2337 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2338 int lane;
2339
2340 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2341 FOR_ALL_LANES {
2342 ctrl->timings[channel][slotrank].lanes[lane].rising =
2343 edge;
2344 ctrl->timings[channel][slotrank].lanes[lane].falling =
2345 edge;
2346 }
2347 program_timings(ctrl, channel);
2348
2349 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002350 volatile u32 tmp;
2351 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
2352 tmp = MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002353 }
2354
2355 wait_428c(channel);
2356 /* DRAM command MRS
2357 * write MR3 MPR enable
2358 * in this mode only RD and RDA are allowed
2359 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002360 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002361 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002362 MCHBAR32(0x4200 + 0x400 * channel) =
2363 (slotrank << 24) | 0x360004;
2364 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002365
2366 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002367 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2368 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2369 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2370 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002371
2372 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002373 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2374 MCHBAR32(0x4238 + 0x400 * channel) =
2375 0x1001 | ((ctrl->CAS + 8) << 16);
2376 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2377 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002378
2379 /* DRAM command MRS
2380 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002381 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2382 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2383 MCHBAR32(0x420c + 0x400 * channel) =
2384 (slotrank << 24) | 0x360000;
2385 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002386
Felix Held9cf1dd22018-07-31 14:52:40 +02002387 // execute command queue
2388 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002389
2390 wait_428c(channel);
2391
2392 FOR_ALL_LANES {
2393 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002394 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002395 }
2396 }
2397 FOR_ALL_LANES {
2398 struct run rn =
2399 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2400 edges[lane] = rn.middle;
2401 if (rn.all) {
2402 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2403 channel, slotrank, lane);
2404 return MAKE_ERR;
2405 }
2406 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2407 lane, edges[lane]);
2408 }
2409 return 0;
2410}
2411
2412int discover_edges(ramctr_timing *ctrl)
2413{
2414 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2415 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2416 int channel, slotrank, lane;
2417 int err;
2418
Felix Held2bb3cdf2018-07-28 00:23:59 +02002419 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002420
2421 toggle_io_reset();
2422
2423 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002424 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002425 }
2426
2427 FOR_ALL_POPULATED_CHANNELS {
2428 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002429 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002430 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002431 volatile u32 tmp;
2432 tmp = MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002433 }
2434
2435 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2436 ctrl->timings[channel][slotrank].lanes[lane].falling =
2437 16;
2438 ctrl->timings[channel][slotrank].lanes[lane].rising =
2439 16;
2440 }
2441
2442 program_timings(ctrl, channel);
2443
2444 FOR_ALL_POPULATED_RANKS {
2445 wait_428c(channel);
2446
2447 /* DRAM command MRS
2448 * MR3 enable MPR
2449 * write MR3 MPR enable
2450 * in this mode only RD and RDA are allowed
2451 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002452 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2453 MCHBAR32(0x4230 + 0x400 * channel) =
2454 0xc01 | (ctrl->tMOD << 16);
2455 MCHBAR32(0x4200 + 0x400 * channel) =
2456 (slotrank << 24) | 0x360004;
2457 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002458
2459 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002460 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2461 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2462 MCHBAR32(0x4204 + 0x400 * channel) =
2463 (slotrank << 24) | 0;
2464 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002465
2466 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002467 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2468 MCHBAR32(0x4238 + 0x400 * channel) =
2469 0x1001 | ((ctrl->CAS + 8) << 16);
2470 MCHBAR32(0x4208 + 0x400 * channel) =
2471 (slotrank << 24) | 0x60000;
2472 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002473
2474 /* DRAM command MRS
2475 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002476 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2477 MCHBAR32(0x423c + 0x400 * channel) =
2478 0xc01 | (ctrl->tMOD << 16);
2479 MCHBAR32(0x420c + 0x400 * channel) =
2480 (slotrank << 24) | 0x360000;
2481 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02002482
2483 // execute command queue
2484 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002485
2486 wait_428c(channel);
2487 }
2488
2489 /* XXX: check any measured value ? */
2490
2491 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2492 ctrl->timings[channel][slotrank].lanes[lane].falling =
2493 48;
2494 ctrl->timings[channel][slotrank].lanes[lane].rising =
2495 48;
2496 }
2497
2498 program_timings(ctrl, channel);
2499
2500 FOR_ALL_POPULATED_RANKS {
2501 wait_428c(channel);
2502
2503 /* DRAM command MRS
2504 * MR3 enable MPR
2505 * write MR3 MPR enable
2506 * in this mode only RD and RDA are allowed
2507 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002508 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2509 MCHBAR32(0x4230 + 0x400 * channel) =
2510 0xc01 | (ctrl->tMOD << 16);
2511 MCHBAR32(0x4200 + 0x400 * channel) =
2512 (slotrank << 24) | 0x360004;
2513 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002514
2515 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002516 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2517 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2518 MCHBAR32(0x4204 + 0x400 * channel) =
2519 (slotrank << 24) | 0;
2520 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002521
2522 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002523 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2524 MCHBAR32(0x4238 + 0x400 * channel) =
2525 0x1001 | ((ctrl->CAS + 8) << 16);
2526 MCHBAR32(0x4208 + 0x400 * channel) =
2527 (slotrank << 24) | 0x60000;
2528 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002529
2530 /* DRAM command MRS
2531 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002532 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2533 MCHBAR32(0x423c + 0x400 * channel) =
2534 0xc01 | (ctrl->tMOD << 16);
2535 MCHBAR32(0x420c + 0x400 * channel) =
2536 (slotrank << 24) | 0x360000;
2537 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002538
Felix Held9cf1dd22018-07-31 14:52:40 +02002539 // execute command queue
2540 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2541
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002542 wait_428c(channel);
2543 }
2544
2545 /* XXX: check any measured value ? */
2546
2547 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002548 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2549 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2550 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002551 }
2552
2553 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002554 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002555 }
2556
2557 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002558 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002559 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2560
2561 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2562 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002563 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002564 if (err)
2565 return err;
2566 }
2567
Felix Held2bb3cdf2018-07-28 00:23:59 +02002568 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002569 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2570
2571 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2572 err = discover_edges_real(ctrl, channel, slotrank,
2573 rising_edges[channel][slotrank]);
2574 if (err)
2575 return err;
2576 }
2577
Felix Held2bb3cdf2018-07-28 00:23:59 +02002578 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002579
2580 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2581 ctrl->timings[channel][slotrank].lanes[lane].falling =
2582 falling_edges[channel][slotrank][lane];
2583 ctrl->timings[channel][slotrank].lanes[lane].rising =
2584 rising_edges[channel][slotrank][lane];
2585 }
2586
2587 FOR_ALL_POPULATED_CHANNELS {
2588 program_timings(ctrl, channel);
2589 }
2590
2591 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002592 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002593 }
2594 return 0;
2595}
2596
2597static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2598 int slotrank, int *edges)
2599{
2600 int edge;
2601 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2602 int statistics[MAX_EDGE_TIMING + 1];
2603 const int reg3000b24[] = { 0, 0xc, 0x2c };
2604 int lane, i;
2605 int lower[NUM_LANES];
2606 int upper[NUM_LANES];
2607 int pat;
2608
2609 FOR_ALL_LANES {
2610 lower[lane] = 0;
2611 upper[lane] = MAX_EDGE_TIMING;
2612 }
2613
2614 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002615 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002616 printram("[%x] = 0x%08x\n",
2617 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2618 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2619 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002620 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002621 printram("using pattern %d\n", pat);
2622 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2623 FOR_ALL_LANES {
2624 ctrl->timings[channel][slotrank].lanes[lane].
2625 rising = edge;
2626 ctrl->timings[channel][slotrank].lanes[lane].
2627 falling = edge;
2628 }
2629 program_timings(ctrl, channel);
2630
2631 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002632 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002633 MCHBAR32(0x4340 + 0x400 * channel +
2634 4 * lane) = 0;
2635 tmp = MCHBAR32(0x400 * channel +
2636 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002637 }
2638 wait_428c(channel);
2639
2640 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002641 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2642 MCHBAR32(0x4230 + 0x400 * channel) =
2643 0x4 | (ctrl->tRCD << 16) |
2644 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
2645 << 10);
2646 MCHBAR32(0x4200 + 0x400 * channel) =
2647 (slotrank << 24) | 0x60000;
2648 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002649
2650 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002651 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2652 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2653 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2654 MCHBAR32(0x4204 + 0x400 * channel) =
2655 slotrank << 24;
2656 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002657
2658 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002659 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2660 MCHBAR32(0x4238 + 0x400 * channel) =
2661 0x4005020 | (max(ctrl->tRTP, 8) << 16);
2662 MCHBAR32(0x4208 + 0x400 * channel) =
2663 slotrank << 24;
2664 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002665
2666 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002667 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2668 MCHBAR32(0x423c + 0x400 * channel) =
2669 0xc01 | (ctrl->tRP << 16);
2670 MCHBAR32(0x420c + 0x400 * channel) =
2671 (slotrank << 24) | 0x60400;
2672 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002673
Felix Held9cf1dd22018-07-31 14:52:40 +02002674 // execute command queue
2675 MCHBAR32(0x4284 + 0x400 * channel) =
2676 RUN_QUEUE_4284(4);
2677
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002678 wait_428c(channel);
2679 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002680 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002681 tmp = MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002682 0x400 * channel + lane * 4);
2683 }
2684
2685 raw_statistics[edge] =
2686 MCHBAR32(0x436c + 0x400 * channel);
2687 }
2688 FOR_ALL_LANES {
2689 struct run rn;
2690 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2691 statistics[edge] =
2692 ! !(raw_statistics[edge] & (1 << lane));
2693 rn = get_longest_zero_run(statistics,
2694 MAX_EDGE_TIMING + 1);
2695 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2696 channel, slotrank, i, rn.start, rn.middle,
2697 rn.end, rn.start + ctrl->edge_offset[i],
2698 rn.end - ctrl->edge_offset[i]);
2699 lower[lane] =
2700 max(rn.start + ctrl->edge_offset[i], lower[lane]);
2701 upper[lane] =
2702 min(rn.end - ctrl->edge_offset[i], upper[lane]);
2703 edges[lane] = (lower[lane] + upper[lane]) / 2;
2704 if (rn.all || (lower[lane] > upper[lane])) {
2705 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2706 channel, slotrank, lane);
2707 return MAKE_ERR;
2708 }
2709 }
2710 }
2711 }
2712
Felix Held2bb3cdf2018-07-28 00:23:59 +02002713 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002714 printram("CPA\n");
2715 return 0;
2716}
2717
2718int discover_edges_write(ramctr_timing *ctrl)
2719{
2720 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2721 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2722 int channel, slotrank, lane;
2723 int err;
2724
2725 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002726 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002727 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2728
2729 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2730 err = discover_edges_write_real(ctrl, channel, slotrank,
2731 falling_edges[channel][slotrank]);
2732 if (err)
2733 return err;
2734 }
2735
Felix Held2bb3cdf2018-07-28 00:23:59 +02002736 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002737 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2738
2739 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2740 err = discover_edges_write_real(ctrl, channel, slotrank,
2741 rising_edges[channel][slotrank]);
2742 if (err)
2743 return err;
2744 }
2745
Felix Held2bb3cdf2018-07-28 00:23:59 +02002746 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002747
2748 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2749 ctrl->timings[channel][slotrank].lanes[lane].falling =
2750 falling_edges[channel][slotrank][lane];
2751 ctrl->timings[channel][slotrank].lanes[lane].rising =
2752 rising_edges[channel][slotrank][lane];
2753 }
2754
2755 FOR_ALL_POPULATED_CHANNELS
2756 program_timings(ctrl, channel);
2757
2758 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002759 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002760 }
2761 return 0;
2762}
2763
2764static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2765{
2766 wait_428c(channel);
2767 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002768 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2769 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002770 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002771 << 10) | (ctrl->tRCD << 16) | 4;
2772 MCHBAR32(0x4200 + 0x400 * channel) =
2773 (slotrank << 24) | 0x60000;
2774 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002775
2776 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002777 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2778 MCHBAR32(0x4234 + 0x400 * channel) =
2779 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2780 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2781 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002782
2783 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002784 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2785 MCHBAR32(0x4238 + 0x400 * channel) =
2786 0x40011e0 | (max(ctrl->tRTP, 8) << 16);
2787 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2788 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002789
2790 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002791 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2792 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2793 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2794 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002795
Felix Held9cf1dd22018-07-31 14:52:40 +02002796 // execute command queue
2797 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2798
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002799 wait_428c(channel);
2800}
2801
2802int discover_timC_write(ramctr_timing *ctrl)
2803{
2804 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2805 int i, pat;
2806
2807 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2808 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2809 int channel, slotrank, lane;
2810
2811 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2812 lower[channel][slotrank][lane] = 0;
2813 upper[channel][slotrank][lane] = MAX_TIMC;
2814 }
2815
Felix Held2bb3cdf2018-07-28 00:23:59 +02002816 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002817 printram("discover timC write:\n");
2818
2819 for (i = 0; i < 3; i++)
2820 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002821 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2822 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002823 udelay(2);
2824 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2825 FOR_ALL_POPULATED_RANKS {
2826 int timC;
2827 u32 raw_statistics[MAX_TIMC + 1];
2828 int statistics[MAX_TIMC + 1];
2829
2830 /* Make sure rn.start < rn.end */
2831 statistics[MAX_TIMC] = 1;
2832
2833 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002834 MCHBAR32(0x4288 + 0x400 * channel) =
2835 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002836 for (timC = 0; timC < MAX_TIMC; timC++) {
2837 FOR_ALL_LANES
2838 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2839 program_timings(ctrl, channel);
2840
2841 test_timC_write (ctrl, channel, slotrank);
2842
2843 raw_statistics[timC] =
2844 MCHBAR32(0x436c + 0x400 * channel);
2845 }
2846 FOR_ALL_LANES {
2847 struct run rn;
2848 for (timC = 0; timC < MAX_TIMC; timC++)
2849 statistics[timC] =
2850 !!(raw_statistics[timC] &
2851 (1 << lane));
2852
2853 rn = get_longest_zero_run(statistics,
2854 MAX_TIMC + 1);
2855 if (rn.all) {
2856 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2857 channel, slotrank, lane);
2858 return MAKE_ERR;
2859 }
2860 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2861 channel, slotrank, i, rn.start,
2862 rn.middle, rn.end,
2863 rn.start + ctrl->timC_offset[i],
2864 rn.end - ctrl->timC_offset[i]);
2865 lower[channel][slotrank][lane] =
2866 max(rn.start + ctrl->timC_offset[i],
2867 lower[channel][slotrank][lane]);
2868 upper[channel][slotrank][lane] =
2869 min(rn.end - ctrl->timC_offset[i],
2870 upper[channel][slotrank][lane]);
2871
2872 }
2873 }
2874 }
2875 }
2876
2877 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002878 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002879 udelay(2);
2880 }
2881
Felix Held2bb3cdf2018-07-28 00:23:59 +02002882 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002883
2884 printram("CPB\n");
2885
2886 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2887 printram("timC %d, %d, %d: %x\n", channel,
2888 slotrank, lane,
2889 (lower[channel][slotrank][lane] +
2890 upper[channel][slotrank][lane]) / 2);
2891 ctrl->timings[channel][slotrank].lanes[lane].timC =
2892 (lower[channel][slotrank][lane] +
2893 upper[channel][slotrank][lane]) / 2;
2894 }
2895 FOR_ALL_POPULATED_CHANNELS {
2896 program_timings(ctrl, channel);
2897 }
2898 return 0;
2899}
2900
2901void normalize_training(ramctr_timing * ctrl)
2902{
2903 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002904 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002905
2906 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2907 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002908 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002909 FOR_ALL_LANES mat =
2910 max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002911 printram("normalize %d, %d, %d: mat %d\n",
2912 channel, slotrank, lane, mat);
2913
2914 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2915 printram("normalize %d, %d, %d: delta %d\n",
2916 channel, slotrank, lane, delta);
2917
2918 ctrl->timings[channel][slotrank].val_4024 += delta;
2919 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002920 }
2921
2922 FOR_ALL_POPULATED_CHANNELS {
2923 program_timings(ctrl, channel);
2924 }
2925}
2926
2927void write_controller_mr(ramctr_timing * ctrl)
2928{
2929 int channel, slotrank;
2930
2931 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002932 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2933 make_mr0(ctrl, slotrank);
2934 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2935 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002936 }
2937}
2938
2939int channel_test(ramctr_timing *ctrl)
2940{
2941 int channel, slotrank, lane;
2942
2943 slotrank = 0;
2944 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002945 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002946 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2947 channel);
2948 return MAKE_ERR;
2949 }
2950 FOR_ALL_POPULATED_CHANNELS {
2951 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2952
Felix Held2bb3cdf2018-07-28 00:23:59 +02002953 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002954 }
2955
2956 for (slotrank = 0; slotrank < 4; slotrank++)
2957 FOR_ALL_CHANNELS
2958 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2959 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002960 MCHBAR32(0x4f40 + 4 * lane) = 0;
2961 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002962 }
2963 wait_428c(channel);
Felix Held9cf1dd22018-07-31 14:52:40 +02002964
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002965 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002966 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2967 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2968 MCHBAR32(0x4200 + (channel << 10)) =
2969 0x00060000 | (slotrank << 24);
2970 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Felix Held9cf1dd22018-07-31 14:52:40 +02002971
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002972 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002973 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2974 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2975 MCHBAR32(0x4204 + (channel << 10)) =
2976 0x00000000 | (slotrank << 24);
2977 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002978
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002979 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002980 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
2981 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
2982 MCHBAR32(0x4208 + (channel << 10)) =
2983 0x00000000 | (slotrank << 24);
2984 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002985
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002986 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002987 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
2988 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
2989 MCHBAR32(0x420c + (channel << 10)) =
2990 0x00060400 | (slotrank << 24);
2991 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
Felix Held9cf1dd22018-07-31 14:52:40 +02002992
2993 // execute command queue
2994 MCHBAR32(0x4284 + (channel << 10)) = RUN_QUEUE_4284(4);
2995
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002996 wait_428c(channel);
2997 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02002998 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002999 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
3000 channel, slotrank, lane);
3001 return MAKE_ERR;
3002 }
3003 }
3004 return 0;
3005}
3006
3007void set_scrambling_seed(ramctr_timing * ctrl)
3008{
3009 int channel;
3010
3011 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
3012 I don't think so. */
3013 static u32 seeds[NUM_CHANNELS][3] = {
3014 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
3015 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
3016 };
3017 FOR_ALL_POPULATED_CHANNELS {
3018 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02003019 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
3020 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
3021 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003022 }
3023}
3024
3025void set_4f8c(void)
3026{
3027 struct cpuid_result cpures;
3028 u32 cpu;
3029
3030 cpures = cpuid(1);
3031 cpu = (cpures.eax);
3032 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3033 MCHBAR32(0x4f8c) = 0x141D1519;
3034 } else {
3035 MCHBAR32(0x4f8c) = 0x551D1519;
3036 }
3037}
3038
3039void prepare_training(ramctr_timing * ctrl)
3040{
3041 int channel;
3042
3043 FOR_ALL_POPULATED_CHANNELS {
3044 // Always drive command bus
Felix Held9fe248f2018-07-31 20:59:45 +02003045 MCHBAR32_OR(0x4004 + 0x400 * channel, 0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003046 }
3047
3048 udelay(1);
3049
3050 FOR_ALL_POPULATED_CHANNELS {
3051 wait_428c(channel);
3052 }
3053}
3054
3055void set_4008c(ramctr_timing * ctrl)
3056{
3057 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003058
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003059 FOR_ALL_POPULATED_CHANNELS {
3060 u32 b20, b4_8_12;
3061 int min_320c = 10000;
3062 int max_320c = -10000;
3063
3064 FOR_ALL_POPULATED_RANKS {
3065 max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c);
3066 min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c);
3067 }
3068
3069 if (max_320c - min_320c > 51)
3070 b20 = 0;
3071 else
3072 b20 = ctrl->ref_card_offset[channel];
3073
3074 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3075 b4_8_12 = 0x3330;
3076 else
3077 b4_8_12 = 0x2220;
3078
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003079 dram_odt_stretch(ctrl, channel);
3080
Felix Held2bb3cdf2018-07-28 00:23:59 +02003081 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003082 0x0a000000 | (b20 << 20) |
3083 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003084 }
3085}
3086
3087void set_42a0(ramctr_timing * ctrl)
3088{
3089 int channel;
3090 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003091 MCHBAR32(0x42a0 + 0x400 * channel) =
3092 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003093 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003094 }
3095}
3096
3097static int encode_5d10(int ns)
3098{
3099 return (ns + 499) / 500;
3100}
3101
3102/* FIXME: values in this function should be hardware revision-dependent. */
3103void final_registers(ramctr_timing * ctrl)
3104{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003105 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3106
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003107 int channel;
3108 int t1_cycles = 0, t1_ns = 0, t2_ns;
3109 int t3_ns;
3110 u32 r32;
3111
Felix Held2bb3cdf2018-07-28 00:23:59 +02003112 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003113
Felix Heldf9b826a2018-07-30 17:56:52 +02003114 FOR_ALL_CHANNELS
3115 MCHBAR32_AND_OR(0x400c + 0x400 * channel, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003116
Patrick Rudolph74203de2017-11-20 11:57:01 +01003117 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003118 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3119 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3120 else
3121 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3122 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3123
Felix Heldf9b826a2018-07-30 17:56:52 +02003124 FOR_ALL_CHANNELS
3125 MCHBAR32(0x4380 + 0x400 * channel) = 0x00000aaa;
3126
Felix Held2bb3cdf2018-07-28 00:23:59 +02003127 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3128 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003129
3130 FOR_ALL_CHANNELS {
3131 switch (ctrl->rankmap[channel]) {
3132 /* Unpopulated channel. */
3133 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003134 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003135 break;
3136 /* Only single-ranked dimms. */
3137 case 1:
3138 case 4:
3139 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003140 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003141 break;
3142 /* Dual-ranked dimms present. */
3143 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003144 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003145 break;
3146 }
3147 }
3148
Felix Held2bb3cdf2018-07-28 00:23:59 +02003149 MCHBAR32(0x5880) = 0xca9171e5;
Felix Held2463aa92018-07-29 21:37:55 +02003150 MCHBAR32_AND_OR(0x5888, ~0xffffff, 0xe4d5d0);
3151 MCHBAR32_AND(0x58a8, ~0x1f);
Felix Heldf9b826a2018-07-30 17:56:52 +02003152
3153 FOR_ALL_CHANNELS
3154 MCHBAR32_AND_OR(0x4294 + 0x400 * channel, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003155
Felix Held9fe248f2018-07-31 20:59:45 +02003156 MCHBAR32_OR(0x5030, 1);
3157 MCHBAR32_OR(0x5030, 0x80);
Felix Held2463aa92018-07-29 21:37:55 +02003158 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003159
3160 /* Find a populated channel. */
3161 FOR_ALL_POPULATED_CHANNELS
3162 break;
3163
Felix Held2bb3cdf2018-07-28 00:23:59 +02003164 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3165 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003166 if (r32 & 0x20000)
3167 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003168 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003169 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3170 if (!(r32 & 0x20000))
3171 t1_ns += 500;
3172
Felix Held2bb3cdf2018-07-28 00:23:59 +02003173 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3174 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003175 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003176 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3177 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003178 }
3179 else
3180 {
3181 t3_ns = 500;
3182 }
3183 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3184 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003185 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3186 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003187 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003188 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003189}
3190
3191void restore_timings(ramctr_timing * ctrl)
3192{
3193 int channel, slotrank, lane;
3194
3195 FOR_ALL_POPULATED_CHANNELS
3196 MCHBAR32(0x4004 + 0x400 * channel) =
3197 ctrl->tRRD
3198 | (ctrl->tRTP << 4)
3199 | (ctrl->tCKE << 8)
3200 | (ctrl->tWTR << 12)
3201 | (ctrl->tFAW << 16)
3202 | (ctrl->tWR << 24)
3203 | (ctrl->cmd_stretch[channel] << 30);
3204
3205 udelay(1);
3206
3207 FOR_ALL_POPULATED_CHANNELS {
3208 wait_428c(channel);
3209 }
3210
3211 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003212 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003213 }
3214
3215 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003216 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003217
3218 FOR_ALL_POPULATED_CHANNELS {
3219 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003220 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003221 }
3222
3223 printram("CPE\n");
3224
Felix Held2bb3cdf2018-07-28 00:23:59 +02003225 MCHBAR32(0x3400) = 0;
3226 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003227
3228 printram("CP5b\n");
3229
3230 FOR_ALL_POPULATED_CHANNELS {
3231 program_timings(ctrl, channel);
3232 }
3233
3234 u32 reg, addr;
3235
3236 while (!(MCHBAR32(0x5084) & 0x10000));
3237 do {
3238 reg = MCHBAR32(0x428c);
3239 } while ((reg & 0x14) == 0);
3240
3241 // Set state of memory controller
3242 MCHBAR32(0x5030) = 0x116;
3243 MCHBAR32(0x4ea0) = 0;
3244
3245 // Wait 500us
3246 udelay(500);
3247
3248 FOR_ALL_CHANNELS {
3249 // Set valid rank CKE
3250 reg = 0;
3251 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3252 addr = 0x400 * channel + 0x42a0;
3253 MCHBAR32(addr) = reg;
3254
3255 // Wait 10ns for ranks to settle
3256 //udelay(0.01);
3257
3258 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3259 MCHBAR32(addr) = reg;
3260
3261 // Write reset using a NOP
3262 write_reset(ctrl);
3263 }
3264
3265 /* mrs commands. */
3266 dram_mrscommands(ctrl);
3267
3268 printram("CP5c\n");
3269
Felix Held2bb3cdf2018-07-28 00:23:59 +02003270 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003271
3272 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003273 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003274 udelay(2);
3275 }
3276
Felix Held2bb3cdf2018-07-28 00:23:59 +02003277 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003278}