blob: 6639fd9a00c2da438a34ae924dd296eebd78d14e [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
65 * Bit 16-20: (number of queued commands - 1) * 4
66 */
67
68static void sfence(void)
69{
70 asm volatile ("sfence");
71}
72
73static void toggle_io_reset(void) {
74 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020075 u32 r32 = MCHBAR32(0x5030);
76 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010077 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020078 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010079 udelay(1);
80}
81
82static u32 get_XOVER_CLK(u8 rankmap)
83{
84 return rankmap << 24;
85}
86
87static u32 get_XOVER_CMD(u8 rankmap)
88{
89 u32 reg;
90
91 // enable xover cmd
92 reg = 0x4000;
93
94 // enable xover ctl
95 if (rankmap & 0x3)
96 reg |= 0x20000;
97
98 if (rankmap & 0xc)
99 reg |= 0x4000000;
100
101 return reg;
102}
103
104/* CAS write latency. To be programmed in MR2.
105 * See DDR3 SPEC for MR2 documentation. */
106u8 get_CWL(u32 tCK)
107{
108 /* Get CWL based on tCK using the following rule: */
109 switch (tCK) {
110 case TCK_1333MHZ:
111 return 12;
112 case TCK_1200MHZ:
113 case TCK_1100MHZ:
114 return 11;
115 case TCK_1066MHZ:
116 case TCK_1000MHZ:
117 return 10;
118 case TCK_933MHZ:
119 case TCK_900MHZ:
120 return 9;
121 case TCK_800MHZ:
122 case TCK_700MHZ:
123 return 8;
124 case TCK_666MHZ:
125 return 7;
126 case TCK_533MHZ:
127 return 6;
128 default:
129 return 5;
130 }
131}
132
133void dram_find_common_params(ramctr_timing *ctrl)
134{
135 size_t valid_dimms;
136 int channel, slot;
137 dimm_info *dimms = &ctrl->info;
138
139 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
140 valid_dimms = 0;
141 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
142 const dimm_attr *dimm = &dimms->dimm[channel][slot];
143 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
144 continue;
145 valid_dimms++;
146
147 /* Find all possible CAS combinations */
148 ctrl->cas_supported &= dimm->cas_supported;
149
150 /* Find the smallest common latencies supported by all DIMMs */
151 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
152 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
153 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
154 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
155 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
156 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
157 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
158 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
159 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
160 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
161 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300162 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
163 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100164 }
165
166 if (!ctrl->cas_supported)
167 die("Unsupported DIMM combination. "
168 "DIMMS do not support common CAS latency");
169 if (!valid_dimms)
170 die("No valid DIMMs found");
171}
172
173void dram_xover(ramctr_timing * ctrl)
174{
175 u32 reg;
176 int channel;
177
178 FOR_ALL_CHANNELS {
179 // enable xover clk
180 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
181 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
182 reg);
183 MCHBAR32(channel * 0x100 + 0xc14) = reg;
184
185 // enable xover ctl & xover cmd
186 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
187 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
188 reg);
189 MCHBAR32(0x100 * channel + 0x320c) = reg;
190 }
191}
192
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100193static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100194{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100195 struct cpuid_result cpures;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100196 u32 reg, addr, cpu, stretch;
197
198 stretch = ctrl->ref_card_offset[channel];
199 /* ODT stretch: Delay ODT signal by stretch value.
200 * Useful for multi DIMM setups on the same channel. */
201 cpures = cpuid(1);
202 cpu = cpures.eax;
203 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
204 if (stretch == 2)
205 stretch = 3;
206 addr = 0x400 * channel + 0x401c;
207 reg = MCHBAR32(addr) & 0xffffc3ff;
208 reg |= (stretch << 12);
209 reg |= (stretch << 10);
210 MCHBAR32(addr) = reg;
211 printram("OTHP Workaround [%x] = %x\n", addr, reg);
212 } else {
213 // OTHP
214 addr = 0x400 * channel + 0x400c;
215 reg = MCHBAR32(addr) & 0xfff0ffff;
216 reg |= (stretch << 16);
217 reg |= (stretch << 18);
218 MCHBAR32(addr) = reg;
219 printram("OTHP [%x] = %x\n", addr, reg);
220 }
221}
222
223void dram_timing_regs(ramctr_timing *ctrl)
224{
225 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100226 int channel;
227
228 FOR_ALL_CHANNELS {
229 // DBP
230 reg = 0;
231 reg |= ctrl->tRCD;
232 reg |= (ctrl->tRP << 4);
233 reg |= (ctrl->CAS << 8);
234 reg |= (ctrl->CWL << 12);
235 reg |= (ctrl->tRAS << 16);
236 printram("DBP [%x] = %x\n", 0x400 * channel + 0x4000, reg);
237 MCHBAR32(0x400 * channel + 0x4000) = reg;
238
239 // RAP
240 reg = 0;
241 reg |= ctrl->tRRD;
242 reg |= (ctrl->tRTP << 4);
243 reg |= (ctrl->tCKE << 8);
244 reg |= (ctrl->tWTR << 12);
245 reg |= (ctrl->tFAW << 16);
246 reg |= (ctrl->tWR << 24);
247 reg |= (3 << 30);
248 printram("RAP [%x] = %x\n", 0x400 * channel + 0x4004, reg);
249 MCHBAR32(0x400 * channel + 0x4004) = reg;
250
251 // OTHP
252 addr = 0x400 * channel + 0x400c;
253 reg = 0;
254 reg |= ctrl->tXPDLL;
255 reg |= (ctrl->tXP << 5);
256 reg |= (ctrl->tAONPD << 8);
257 reg |= 0xa0000;
258 printram("OTHP [%x] = %x\n", addr, reg);
259 MCHBAR32(addr) = reg;
260
261 MCHBAR32(0x400 * channel + 0x4014) = 0;
262
263 MCHBAR32(addr) |= 0x00020000;
264
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100265 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100266
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100267 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200268 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100269 * The tREFIx9 field should be programmed to minimum of
270 * 8.9*tREFI (to allow for possible delays from ZQ or
271 * isoc) and tRASmax (70us) divided by 1024.
272 */
273 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
274
275 reg = ((ctrl->tREFI & 0xffff) << 0) |
276 ((ctrl->tRFC & 0x1ff) << 16) |
277 (((val32 / 1024) & 0x7f) << 25);
278 printram("REFI [%x] = %x\n", 0x400 * channel + 0x4298, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100279 MCHBAR32(0x400 * channel + 0x4298) = reg;
280
281 MCHBAR32(0x400 * channel + 0x4294) |= 0xff;
282
283 // SRFTP
284 reg = 0;
285 val32 = tDLLK;
286 reg = (reg & ~0xfff) | val32;
287 val32 = ctrl->tXSOffset;
288 reg = (reg & ~0xf000) | (val32 << 12);
289 val32 = tDLLK - ctrl->tXSOffset;
290 reg = (reg & ~0x3ff0000) | (val32 << 16);
291 val32 = ctrl->tMOD - 8;
292 reg = (reg & ~0xf0000000) | (val32 << 28);
293 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
294 reg);
295 MCHBAR32(0x400 * channel + 0x42a4) = reg;
296 }
297}
298
299void dram_dimm_mapping(ramctr_timing *ctrl)
300{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100301 int channel;
302 dimm_info *info = &ctrl->info;
303
304 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200305 dimm_attr *dimmA, *dimmB;
306 u32 reg = 0;
307
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100308 if (info->dimm[channel][0].size_mb >=
309 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100310 dimmA = &info->dimm[channel][0];
311 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200312 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100313 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100314 dimmA = &info->dimm[channel][1];
315 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200316 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100317 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100318
Nico Huberac4f2162017-10-01 18:14:43 +0200319 if (dimmA && (dimmA->ranks > 0)) {
320 reg |= dimmA->size_mb / 256;
321 reg |= (dimmA->ranks - 1) << 17;
322 reg |= (dimmA->width / 8 - 1) << 19;
323 }
324
325 if (dimmB && (dimmB->ranks > 0)) {
326 reg |= (dimmB->size_mb / 256) << 8;
327 reg |= (dimmB->ranks - 1) << 18;
328 reg |= (dimmB->width / 8 - 1) << 20;
329 }
330
331 reg |= 1 << 21; /* rank interleave */
332 reg |= 1 << 22; /* enhanced interleave */
333
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100334 if ((dimmA && (dimmA->ranks > 0))
335 || (dimmB && (dimmB->ranks > 0))) {
336 ctrl->mad_dimm[channel] = reg;
337 } else {
338 ctrl->mad_dimm[channel] = 0;
339 }
340 }
341}
342
343void dram_dimm_set_mapping(ramctr_timing * ctrl)
344{
345 int channel;
346 FOR_ALL_CHANNELS {
347 MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel];
348 }
349}
350
351void dram_zones(ramctr_timing * ctrl, int training)
352{
353 u32 reg, ch0size, ch1size;
354 u8 val;
355 reg = 0;
356 val = 0;
357 if (training) {
358 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
359 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
360 } else {
361 ch0size = ctrl->channel_size_mb[0];
362 ch1size = ctrl->channel_size_mb[1];
363 }
364
365 if (ch0size >= ch1size) {
366 reg = MCHBAR32(0x5014);
367 val = ch1size / 256;
368 reg = (reg & ~0xff000000) | val << 24;
369 reg = (reg & ~0xff0000) | (2 * val) << 16;
370 MCHBAR32(0x5014) = reg;
371 MCHBAR32(0x5000) = 0x24;
372 } else {
373 reg = MCHBAR32(0x5014);
374 val = ch0size / 256;
375 reg = (reg & ~0xff000000) | val << 24;
376 reg = (reg & ~0xff0000) | (2 * val) << 16;
377 MCHBAR32(0x5014) = reg;
378 MCHBAR32(0x5000) = 0x21;
379 }
380}
381
382#define HOST_BRIDGE PCI_DEVFN(0, 0)
383#define DEFAULT_TCK TCK_800MHZ
384
385unsigned int get_mem_min_tck(void)
386{
387 u32 reg32;
388 u8 rev;
389 const struct device *dev;
390 const struct northbridge_intel_sandybridge_config *cfg = NULL;
391
392 dev = dev_find_slot(0, HOST_BRIDGE);
393 if (dev)
394 cfg = dev->chip_info;
395
396 /* If this is zero, it just means devicetree.cb didn't set it */
397 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Patrick Rudolphb794a692017-08-08 13:13:51 +0200398 if (IS_ENABLED(CONFIG_NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
399 return TCK_1333MHZ;
400
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100401 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
402
403 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
404 /* read Capabilities A Register DMFC bits */
405 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
406 reg32 &= 0x7;
407
408 switch (reg32) {
409 case 7: return TCK_533MHZ;
410 case 6: return TCK_666MHZ;
411 case 5: return TCK_800MHZ;
412 /* reserved: */
413 default:
414 break;
415 }
416 } else {
417 /* read Capabilities B Register DMFC bits */
418 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
419 reg32 = (reg32 >> 4) & 0x7;
420
421 switch (reg32) {
422 case 7: return TCK_533MHZ;
423 case 6: return TCK_666MHZ;
424 case 5: return TCK_800MHZ;
425 case 4: return TCK_933MHZ;
426 case 3: return TCK_1066MHZ;
427 case 2: return TCK_1200MHZ;
428 case 1: return TCK_1333MHZ;
429 /* reserved: */
430 default:
431 break;
432 }
433 }
434 return DEFAULT_TCK;
435 } else {
436 if (cfg->max_mem_clock_mhz >= 1066)
437 return TCK_1066MHZ;
438 else if (cfg->max_mem_clock_mhz >= 933)
439 return TCK_933MHZ;
440 else if (cfg->max_mem_clock_mhz >= 800)
441 return TCK_800MHZ;
442 else if (cfg->max_mem_clock_mhz >= 666)
443 return TCK_666MHZ;
444 else if (cfg->max_mem_clock_mhz >= 533)
445 return TCK_533MHZ;
446 else
447 return TCK_400MHZ;
448 }
449}
450
451#define DEFAULT_PCI_MMIO_SIZE 2048
452
453static unsigned int get_mmio_size(void)
454{
455 const struct device *dev;
456 const struct northbridge_intel_sandybridge_config *cfg = NULL;
457
458 dev = dev_find_slot(0, HOST_BRIDGE);
459 if (dev)
460 cfg = dev->chip_info;
461
462 /* If this is zero, it just means devicetree.cb didn't set it */
463 if (!cfg || cfg->pci_mmio_size == 0)
464 return DEFAULT_PCI_MMIO_SIZE;
465 else
466 return cfg->pci_mmio_size;
467}
468
469void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
470{
471 u32 reg, val, reclaim;
472 u32 tom, gfxstolen, gttsize;
473 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
474 tsegbase, mestolenbase;
475 size_t tsegbasedelta, remapbase, remaplimit;
476 uint16_t ggc;
477
478 mmiosize = get_mmio_size();
479
480 ggc = pci_read_config16(NORTHBRIDGE, GGC);
481 if (!(ggc & 2)) {
482 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
483 gttsize = ((ggc >> 8) & 0x3);
484 } else {
485 gfxstolen = 0;
486 gttsize = 0;
487 }
488
489 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
490
491 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
492
493 mestolenbase = tom - me_uma_size;
494
495 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
496 tom - me_uma_size);
497 gfxstolenbase = toludbase - gfxstolen;
498 gttbase = gfxstolenbase - gttsize;
499
500 tsegbase = gttbase - tsegsize;
501
502 // Round tsegbase down to nearest address aligned to tsegsize
503 tsegbasedelta = tsegbase & (tsegsize - 1);
504 tsegbase &= ~(tsegsize - 1);
505
506 gttbase -= tsegbasedelta;
507 gfxstolenbase -= tsegbasedelta;
508 toludbase -= tsegbasedelta;
509
510 // Test if it is possible to reclaim a hole in the RAM addressing
511 if (tom - me_uma_size > toludbase) {
512 // Reclaim is possible
513 reclaim = 1;
514 remapbase = MAX(4096, tom - me_uma_size);
515 remaplimit =
516 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
517 touudbase = remaplimit + 1;
518 } else {
519 // Reclaim not possible
520 reclaim = 0;
521 touudbase = tom - me_uma_size;
522 }
523
524 // Update memory map in pci-e configuration space
525 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
526
527 // TOM (top of memory)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300528 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100529 val = tom & 0xfff;
530 reg = (reg & ~0xfff00000) | (val << 20);
531 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300532 pci_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100533
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300534 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100535 val = tom & 0xfffff000;
536 reg = (reg & ~0x000fffff) | (val >> 12);
537 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300538 pci_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100539
540 // TOLUD (top of low used dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300541 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xbc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100542 val = toludbase & 0xfff;
543 reg = (reg & ~0xfff00000) | (val << 20);
544 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xbc, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300545 pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100546
547 // TOUUD LSB (top of upper usable dram)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300548 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xa8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100549 val = touudbase & 0xfff;
550 reg = (reg & ~0xfff00000) | (val << 20);
551 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xa8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300552 pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100553
554 // TOUUD MSB
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300555 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xac);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100556 val = touudbase & 0xfffff000;
557 reg = (reg & ~0x000fffff) | (val >> 12);
558 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xac, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300559 pci_write_config32(PCI_DEV(0, 0, 0), 0xac, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100560
561 if (reclaim) {
562 // REMAP BASE
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300563 pci_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20);
564 pci_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100565
566 // REMAP LIMIT
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300567 pci_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20);
568 pci_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100569 }
570 // TSEG
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300571 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100572 val = tsegbase & 0xfff;
573 reg = (reg & ~0xfff00000) | (val << 20);
574 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb8, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300575 pci_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100576
577 // GFX stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300578 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100579 val = gfxstolenbase & 0xfff;
580 reg = (reg & ~0xfff00000) | (val << 20);
581 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb0, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300582 pci_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100583
584 // GTT stolen memory
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300585 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0xb4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100586 val = gttbase & 0xfff;
587 reg = (reg & ~0xfff00000) | (val << 20);
588 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0xb4, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300589 pci_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100590
591 if (me_uma_size) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300592 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x7c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100593 val = (0x80000 - me_uma_size) & 0xfffff000;
594 reg = (reg & ~0x000fffff) | (val >> 12);
595 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x7c, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300596 pci_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100597
598 // ME base
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300599 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x70);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100600 val = mestolenbase & 0xfff;
601 reg = (reg & ~0xfff00000) | (val << 20);
602 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x70, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300603 pci_write_config32(PCI_DEV(0, 0, 0), 0x70, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100604
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300605 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x74);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100606 val = mestolenbase & 0xfffff000;
607 reg = (reg & ~0x000fffff) | (val >> 12);
608 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x74, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300609 pci_write_config32(PCI_DEV(0, 0, 0), 0x74, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100610
611 // ME mask
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300612 reg = pci_read_config32(PCI_DEV(0, 0, 0), 0x78);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100613 val = (0x80000 - me_uma_size) & 0xfff;
614 reg = (reg & ~0xfff00000) | (val << 20);
615 reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem
616
617 reg = (reg & ~0x800) | (1 << 11); // set ME memory enable
618 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", 0x78, reg);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +0300619 pci_write_config32(PCI_DEV(0, 0, 0), 0x78, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100620 }
621}
622
623static void wait_428c(int channel)
624{
625 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200626 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100627 return;
628 }
629}
630
631static void write_reset(ramctr_timing * ctrl)
632{
633 int channel, slotrank;
634
635 /* choose a populated channel. */
636 channel = (ctrl->rankmap[0]) ? 0 : 1;
637
638 wait_428c(channel);
639
640 /* choose a populated rank. */
641 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
642
643 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200644 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
645 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100646
Felix Held2bb3cdf2018-07-28 00:23:59 +0200647 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100648
Felix Held2bb3cdf2018-07-28 00:23:59 +0200649 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100650
Felix Held2bb3cdf2018-07-28 00:23:59 +0200651 MCHBAR32(0x4284 + 0x400 * channel) = 0x400001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100652 wait_428c(channel);
653}
654
655void dram_jedecreset(ramctr_timing * ctrl)
656{
657 u32 reg, addr;
658 int channel;
659
660 while (!(MCHBAR32(0x5084) & 0x10000));
661 do {
662 reg = MCHBAR32(0x428c);
663 } while ((reg & 0x14) == 0);
664
665 // Set state of memory controller
666 reg = 0x112;
667 MCHBAR32(0x5030) = reg;
668 MCHBAR32(0x4ea0) = 0;
669 reg |= 2; //ddr reset
670 MCHBAR32(0x5030) = reg;
671
672 // Assert dimm reset signal
673 reg = MCHBAR32(0x5030);
674 reg &= ~0x2;
675 MCHBAR32(0x5030) = reg;
676
677 // Wait 200us
678 udelay(200);
679
680 // Deassert dimm reset signal
681 MCHBAR32(0x5030) |= 2;
682
683 // Wait 500us
684 udelay(500);
685
686 // Enable DCLK
687 MCHBAR32(0x5030) |= 4;
688
689 // XXX Wait 20ns
690 udelay(1);
691
692 FOR_ALL_CHANNELS {
693 // Set valid rank CKE
694 reg = 0;
695 reg = (reg & ~0xf) | ctrl->rankmap[channel];
696 addr = 0x400 * channel + 0x42a0;
697 MCHBAR32(addr) = reg;
698
699 // Wait 10ns for ranks to settle
700 //udelay(0.01);
701
702 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
703 MCHBAR32(addr) = reg;
704
705 // Write reset using a NOP
706 write_reset(ctrl);
707 }
708}
709
710static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
711{
712 /* Get ODT based on rankmap: */
713 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
714 + ((ctrl->rankmap[channel] >> 2) & 1);
715
716 if (dimms_per_ch == 1) {
717 return (const odtmap){60, 60};
718 } else {
719 return (const odtmap){120, 30};
720 }
721}
722
723static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
724 int reg, u32 val)
725{
726 wait_428c(channel);
727
728 if (ctrl->rank_mirror[channel][slotrank]) {
729 /* DDR3 Rank1 Address mirror
730 * swap the following pins:
731 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
732 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
733 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
734 | ((val & 0xa8) << 1);
735 }
736
737 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200738 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
739 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
740 MCHBAR32(0x4200 + 0x400 * channel) =
741 (slotrank << 24) | (reg << 20) | val | 0x60000;
742 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100743
744 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200745 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
746 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
747 MCHBAR32(0x4204 + 0x400 * channel) =
748 (slotrank << 24) | (reg << 20) | val | 0x60000;
749 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100750
751 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200752 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
753 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
754 MCHBAR32(0x4208 + 0x400 * channel) =
755 (slotrank << 24) | (reg << 20) | val | 0x60000;
756 MCHBAR32(0x4218 + 0x400 * channel) = 0;
757 MCHBAR32(0x4284 + 0x400 * channel) = 0x80001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100758}
759
760static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
761{
762 u16 mr0reg, mch_cas, mch_wr;
763 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 +0100764 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100765
766 /* DLL Reset - self clearing - set after CLK frequency has been changed */
767 mr0reg = 0x100;
768
769 // Convert CAS to MCH register friendly
770 if (ctrl->CAS < 12) {
771 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
772 } else {
773 mch_cas = (u16) (ctrl->CAS - 12);
774 mch_cas = ((mch_cas << 1) | 0x1);
775 }
776
777 // Convert tWR to MCH register friendly
778 mch_wr = mch_wr_t[ctrl->tWR - 5];
779
780 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
781 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
782 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
783
784 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100785 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100786 return mr0reg;
787}
788
789static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
790{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200791 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100792}
793
794static u32 encode_odt(u32 odt)
795{
796 switch (odt) {
797 case 30:
798 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
799 case 60:
800 return (1 << 2); // RZQ/4
801 case 120:
802 return (1 << 6); // RZQ/2
803 default:
804 case 0:
805 return 0;
806 }
807}
808
809static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
810{
811 odtmap odt;
812 u32 mr1reg;
813
814 odt = get_ODT(ctrl, rank, channel);
815 mr1reg = 0x2;
816
817 mr1reg |= encode_odt(odt.rttnom);
818
819 return mr1reg;
820}
821
822static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
823{
824 u16 mr1reg;
825
826 mr1reg = make_mr1(ctrl, rank, channel);
827
828 write_mrreg(ctrl, channel, rank, 1, mr1reg);
829}
830
831static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
832{
833 u16 pasr, cwl, mr2reg;
834 odtmap odt;
835 int srt;
836
837 pasr = 0;
838 cwl = ctrl->CWL - 5;
839 odt = get_ODT(ctrl, rank, channel);
840
841 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
842
843 mr2reg = 0;
844 mr2reg = (mr2reg & ~0x7) | pasr;
845 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
846 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
847 mr2reg = (mr2reg & ~0x80) | (srt << 7);
848 mr2reg |= (odt.rttwr / 60) << 9;
849
850 write_mrreg(ctrl, channel, rank, 2, mr2reg);
851}
852
853static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
854{
855 write_mrreg(ctrl, channel, rank, 3, 0);
856}
857
858void dram_mrscommands(ramctr_timing * ctrl)
859{
860 u8 slotrank;
861 u32 reg, addr;
862 int channel;
863
864 FOR_ALL_POPULATED_CHANNELS {
865 FOR_ALL_POPULATED_RANKS {
866 // MR2
867 dram_mr2(ctrl, slotrank, channel);
868
869 // MR3
870 dram_mr3(ctrl, slotrank, channel);
871
872 // MR1
873 dram_mr1(ctrl, slotrank, channel);
874
875 // MR0
876 dram_mr0(ctrl, slotrank, channel);
877 }
878 }
879
880 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200881 MCHBAR32(0x4e20) = 0x7;
882 MCHBAR32(0x4e30) = 0xf1001;
883 MCHBAR32(0x4e00) = 0x60002;
884 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100885
886 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200887 MCHBAR32(0x4e24) = 0x1f003;
888 MCHBAR32(0x4e34) = 0x1901001;
889 MCHBAR32(0x4e04) = 0x60400;
890 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100891
892 /* execute command queue on all channels ? */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200893 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100894
895 // Drain
896 FOR_ALL_CHANNELS {
897 // Wait for ref drained
898 wait_428c(channel);
899 }
900
901 // Refresh enable
902 MCHBAR32(0x5030) |= 8;
903
904 FOR_ALL_POPULATED_CHANNELS {
905 addr = 0x400 * channel + 0x4020;
906 reg = MCHBAR32(addr);
907 reg &= ~0x200000;
908 MCHBAR32(addr) = reg;
909
910 wait_428c(channel);
911
912 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
913
914 // Drain
915 wait_428c(channel);
916
917 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200918 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
919 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
920 MCHBAR32(0x4200 + 0x400 * channel) =
921 (slotrank << 24) | 0x60000;
922 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
923 MCHBAR32(0x4284 + 0x400 * channel) = 0x1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100924
925 // Drain
926 wait_428c(channel);
927 }
928}
929
930static const u32 lane_registers[] = {
931 0x0000, 0x0200, 0x0400, 0x0600,
932 0x1000, 0x1200, 0x1400, 0x1600,
933 0x0800
934};
935
936void program_timings(ramctr_timing * ctrl, int channel)
937{
938 u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028;
939 int lane;
940 int slotrank, slot;
941 int full_shift = 0;
942 u16 slot320c[NUM_SLOTS];
943
944 FOR_ALL_POPULATED_RANKS {
945 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
946 full_shift = -ctrl->timings[channel][slotrank].val_320c;
947 }
948
949 for (slot = 0; slot < NUM_SLOTS; slot++)
950 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
951 case 0:
952 default:
953 slot320c[slot] = 0x7f;
954 break;
955 case 1:
956 slot320c[slot] =
957 ctrl->timings[channel][2 * slot + 0].val_320c +
958 full_shift;
959 break;
960 case 2:
961 slot320c[slot] =
962 ctrl->timings[channel][2 * slot + 1].val_320c +
963 full_shift;
964 break;
965 case 3:
966 slot320c[slot] =
967 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200968 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100969 full_shift;
970 break;
971 }
972
973 /* enable CMD XOVER */
974 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
975 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
976 reg32 |= (slot320c[1] & 0x7f) << 18;
977 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
978
979 MCHBAR32(0x320c + 0x100 * channel) = reg32;
980
981 /* enable CLK XOVER */
982 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
983 reg_c18 = 0;
984
985 FOR_ALL_POPULATED_RANKS {
986 int shift =
987 ctrl->timings[channel][slotrank].val_320c + full_shift;
988 int offset_val_c14;
989 if (shift < 0)
990 shift = 0;
991 offset_val_c14 = ctrl->reg_c14_offset + shift;
992 /* set CLK phase shift */
993 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
994 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
995 }
996
997 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
998 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
999
1000 reg_4028 = MCHBAR32(0x4028 + 0x400 * channel);
1001 reg_4028 &= 0xffff0000;
1002
1003 reg_4024 = 0;
1004
1005 FOR_ALL_POPULATED_RANKS {
1006 int post_timA_min_high = 7, post_timA_max_high = 0;
1007 int pre_timA_min_high = 7, pre_timA_max_high = 0;
1008 int shift_402x = 0;
1009 int shift =
1010 ctrl->timings[channel][slotrank].val_320c + full_shift;
1011
1012 if (shift < 0)
1013 shift = 0;
1014
1015 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001016 post_timA_min_high = MIN(post_timA_min_high,
1017 (ctrl->timings[channel][slotrank].lanes[lane].
1018 timA + shift) >> 6);
1019 pre_timA_min_high = MIN(pre_timA_min_high,
1020 ctrl->timings[channel][slotrank].lanes[lane].
1021 timA >> 6);
1022 post_timA_max_high = MAX(post_timA_max_high,
1023 (ctrl->timings[channel][slotrank].lanes[lane].
1024 timA + shift) >> 6);
1025 pre_timA_max_high = MAX(pre_timA_max_high,
1026 ctrl->timings[channel][slotrank].lanes[lane].
1027 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001028 }
1029
1030 if (pre_timA_max_high - pre_timA_min_high <
1031 post_timA_max_high - post_timA_min_high)
1032 shift_402x = +1;
1033 else if (pre_timA_max_high - pre_timA_min_high >
1034 post_timA_max_high - post_timA_min_high)
1035 shift_402x = -1;
1036
1037 reg_4028 |=
1038 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1039 post_timA_min_high) << (4 * slotrank);
1040 reg_4024 |=
1041 (ctrl->timings[channel][slotrank].val_4024 +
1042 shift_402x) << (8 * slotrank);
1043
1044 FOR_ALL_LANES {
1045 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1046 4 * slotrank)
1047 =
1048 (((ctrl->timings[channel][slotrank].lanes[lane].
1049 timA + shift) & 0x3f)
1050 |
1051 ((ctrl->timings[channel][slotrank].lanes[lane].
1052 rising + shift) << 8)
1053 |
1054 (((ctrl->timings[channel][slotrank].lanes[lane].
1055 timA + shift -
1056 (post_timA_min_high << 6)) & 0x1c0) << 10)
1057 | ((ctrl->timings[channel][slotrank].lanes[lane].
1058 falling + shift) << 20));
1059
1060 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1061 4 * slotrank)
1062 =
1063 (((ctrl->timings[channel][slotrank].lanes[lane].
1064 timC + shift) & 0x3f)
1065 |
1066 (((ctrl->timings[channel][slotrank].lanes[lane].
1067 timB + shift) & 0x3f) << 8)
1068 |
1069 (((ctrl->timings[channel][slotrank].lanes[lane].
1070 timB + shift) & 0x1c0) << 9)
1071 |
1072 (((ctrl->timings[channel][slotrank].lanes[lane].
1073 timC + shift) & 0x40) << 13));
1074 }
1075 }
1076 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
1077 MCHBAR32(0x4028 + 0x400 * channel) = reg_4028;
1078}
1079
1080static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1081{
1082 wait_428c(channel);
1083
1084 /* DRAM command MRS
1085 * write MR3 MPR enable
1086 * in this mode only RD and RDA are allowed
1087 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001088 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1089 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1090 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1091 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001092
1093 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001094 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1095 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1096 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1097 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001098
1099 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001100 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1101 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1102 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1103 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001104
1105 /* DRAM command MRS
1106 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001107 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1108 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1109 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1110 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001111
Felix Held2bb3cdf2018-07-28 00:23:59 +02001112 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001113
1114 wait_428c(channel);
1115}
1116
1117static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1118 int lane)
1119{
1120 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001121 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001122 ((timA / 32) & 1) * 4)
1123 >> (timA % 32)) & 1);
1124}
1125
1126struct run {
1127 int middle;
1128 int end;
1129 int start;
1130 int all;
1131 int length;
1132};
1133
1134static struct run get_longest_zero_run(int *seq, int sz)
1135{
1136 int i, ls;
1137 int bl = 0, bs = 0;
1138 struct run ret;
1139
1140 ls = 0;
1141 for (i = 0; i < 2 * sz; i++)
1142 if (seq[i % sz]) {
1143 if (i - ls > bl) {
1144 bl = i - ls;
1145 bs = ls;
1146 }
1147 ls = i + 1;
1148 }
1149 if (bl == 0) {
1150 ret.middle = sz / 2;
1151 ret.start = 0;
1152 ret.end = sz;
1153 ret.all = 1;
1154 return ret;
1155 }
1156
1157 ret.start = bs % sz;
1158 ret.end = (bs + bl - 1) % sz;
1159 ret.middle = (bs + (bl - 1) / 2) % sz;
1160 ret.length = bl;
1161 ret.all = 0;
1162
1163 return ret;
1164}
1165
1166static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1167 int slotrank, int *upperA)
1168{
1169 int timA;
1170 int statistics[NUM_LANES][128];
1171 int lane;
1172
1173 for (timA = 0; timA < 128; timA++) {
1174 FOR_ALL_LANES {
1175 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1176 }
1177 program_timings(ctrl, channel);
1178
1179 test_timA(ctrl, channel, slotrank);
1180
1181 FOR_ALL_LANES {
1182 statistics[lane][timA] =
1183 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001184 }
1185 }
1186 FOR_ALL_LANES {
1187 struct run rn = get_longest_zero_run(statistics[lane], 128);
1188 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1189 upperA[lane] = rn.end;
1190 if (upperA[lane] < rn.middle)
1191 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001192 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001193 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001194 }
1195}
1196
1197static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1198 int *upperA)
1199{
1200 int timA_delta;
1201 int statistics[NUM_LANES][51];
1202 int lane, i;
1203
1204 memset(statistics, 0, sizeof(statistics));
1205
1206 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1207 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1208 timA = upperA[lane] + timA_delta + 0x40;
1209 program_timings(ctrl, channel);
1210
1211 for (i = 0; i < 100; i++) {
1212 test_timA(ctrl, channel, slotrank);
1213 FOR_ALL_LANES {
1214 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001215 does_lane_work(ctrl, channel, slotrank,
1216 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001217 }
1218 }
1219 }
1220 FOR_ALL_LANES {
1221 int last_zero, first_all;
1222
1223 for (last_zero = -25; last_zero <= 25; last_zero++)
1224 if (statistics[lane][last_zero + 25])
1225 break;
1226 last_zero--;
1227 for (first_all = -25; first_all <= 25; first_all++)
1228 if (statistics[lane][first_all + 25] == 100)
1229 break;
1230
1231 printram("lane %d: %d, %d\n", lane, last_zero,
1232 first_all);
1233
1234 ctrl->timings[channel][slotrank].lanes[lane].timA =
1235 (last_zero + first_all) / 2 + upperA[lane];
1236 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1237 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1238 }
1239}
1240
1241static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1242 int *upperA)
1243{
1244 int works[NUM_LANES];
1245 int lane;
1246 while (1) {
1247 int all_works = 1, some_works = 0;
1248 program_timings(ctrl, channel);
1249 test_timA(ctrl, channel, slotrank);
1250 FOR_ALL_LANES {
1251 works[lane] =
1252 !does_lane_work(ctrl, channel, slotrank, lane);
1253 if (works[lane])
1254 some_works = 1;
1255 else
1256 all_works = 0;
1257 }
1258 if (all_works)
1259 return 0;
1260 if (!some_works) {
1261 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1262 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1263 channel, slotrank);
1264 return MAKE_ERR;
1265 }
1266 ctrl->timings[channel][slotrank].val_4024 -= 2;
1267 printram("4024 -= 2;\n");
1268 continue;
1269 }
1270 ctrl->timings[channel][slotrank].val_4028 += 2;
1271 printram("4028 += 2;\n");
1272 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1273 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1274 channel, slotrank);
1275 return MAKE_ERR;
1276 }
1277 FOR_ALL_LANES if (works[lane]) {
1278 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1279 128;
1280 upperA[lane] += 128;
1281 printram("increment %d, %d, %d\n", channel,
1282 slotrank, lane);
1283 }
1284 }
1285 return 0;
1286}
1287
1288struct timA_minmax {
1289 int timA_min_high, timA_max_high;
1290};
1291
1292static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1293 struct timA_minmax *mnmx)
1294{
1295 int lane;
1296 mnmx->timA_min_high = 7;
1297 mnmx->timA_max_high = 0;
1298
1299 FOR_ALL_LANES {
1300 if (mnmx->timA_min_high >
1301 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1302 mnmx->timA_min_high =
1303 (ctrl->timings[channel][slotrank].lanes[lane].
1304 timA >> 6);
1305 if (mnmx->timA_max_high <
1306 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1307 mnmx->timA_max_high =
1308 (ctrl->timings[channel][slotrank].lanes[lane].
1309 timA >> 6);
1310 }
1311}
1312
1313static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1314 struct timA_minmax *mnmx)
1315{
1316 struct timA_minmax post;
1317 int shift_402x = 0;
1318
1319 /* Get changed maxima. */
1320 pre_timA_change(ctrl, channel, slotrank, &post);
1321
1322 if (mnmx->timA_max_high - mnmx->timA_min_high <
1323 post.timA_max_high - post.timA_min_high)
1324 shift_402x = +1;
1325 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1326 post.timA_max_high - post.timA_min_high)
1327 shift_402x = -1;
1328 else
1329 shift_402x = 0;
1330
1331 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1332 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1333 printram("4024 += %d;\n", shift_402x);
1334 printram("4028 += %d;\n", shift_402x);
1335}
1336
1337/* Compensate the skew between DQS and DQs.
1338 * To ease PCB design a small skew between Data Strobe signals and
1339 * Data Signals is allowed.
1340 * The controller has to measure and compensate this skew for every byte-lane.
1341 * By delaying either all DQs signals or DQS signal, a full phase
1342 * shift can be introduced.
1343 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1344 *
1345 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1346 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1347 * The memory controller iterates over all possible values to do a full phase shift
1348 * and issues read commands.
1349 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1350 * 0xFF 0x00 0xFF ...
1351 * Once the controller has detected this pattern a bit in the result register is
1352 * set for the current phase shift.
1353 */
1354int read_training(ramctr_timing * ctrl)
1355{
1356 int channel, slotrank, lane;
1357 int err;
1358
1359 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1360 int all_high, some_high;
1361 int upperA[NUM_LANES];
1362 struct timA_minmax mnmx;
1363
Felix Held2bb3cdf2018-07-28 00:23:59 +02001364 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001365
Felix Held2bb3cdf2018-07-28 00:23:59 +02001366 /* DRAM command PREA */
1367 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1368 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1369 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1370 MCHBAR32(0x4210 + 0x400 * channel) = 0;
1371 MCHBAR32(0x4284 + 0x400 * channel) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001372
Felix Held2bb3cdf2018-07-28 00:23:59 +02001373 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001374
Felix Held2bb3cdf2018-07-28 00:23:59 +02001375 ctrl->timings[channel][slotrank].val_4028 = 4;
1376 ctrl->timings[channel][slotrank].val_4024 = 55;
1377 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001378
Felix Held2bb3cdf2018-07-28 00:23:59 +02001379 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001380
Felix Held2bb3cdf2018-07-28 00:23:59 +02001381 all_high = 1;
1382 some_high = 0;
1383 FOR_ALL_LANES {
1384 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1385 0x40)
1386 some_high = 1;
1387 else
1388 all_high = 0;
1389 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001390
1391 if (all_high) {
1392 ctrl->timings[channel][slotrank].val_4028--;
1393 printram("4028--;\n");
1394 FOR_ALL_LANES {
1395 ctrl->timings[channel][slotrank].lanes[lane].
1396 timA -= 0x40;
1397 upperA[lane] -= 0x40;
1398
1399 }
1400 } else if (some_high) {
1401 ctrl->timings[channel][slotrank].val_4024++;
1402 ctrl->timings[channel][slotrank].val_4028++;
1403 printram("4024++;\n");
1404 printram("4028++;\n");
1405 }
1406
1407 program_timings(ctrl, channel);
1408
1409 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1410
1411 err = discover_402x(ctrl, channel, slotrank, upperA);
1412 if (err)
1413 return err;
1414
1415 post_timA_change(ctrl, channel, slotrank, &mnmx);
1416 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1417
1418 discover_timA_fine(ctrl, channel, slotrank, upperA);
1419
1420 post_timA_change(ctrl, channel, slotrank, &mnmx);
1421 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1422
1423 FOR_ALL_LANES {
1424 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1425 }
1426 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1427 printram("4028 -= %d;\n", mnmx.timA_min_high);
1428
1429 post_timA_change(ctrl, channel, slotrank, &mnmx);
1430
1431 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1432 ctrl->timings[channel][slotrank].val_4024,
1433 ctrl->timings[channel][slotrank].val_4028);
1434
1435 printram("final results:\n");
1436 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001437 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1438 lane,
1439 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001440
Felix Held2bb3cdf2018-07-28 00:23:59 +02001441 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001442
1443 toggle_io_reset();
1444 }
1445
1446 FOR_ALL_POPULATED_CHANNELS {
1447 program_timings(ctrl, channel);
1448 }
1449 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001450 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001451 }
1452 return 0;
1453}
1454
1455static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1456{
1457 int lane;
1458
1459 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001460 volatile u32 tmp;
1461 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
1462 tmp = MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001463 }
1464
1465 wait_428c(channel);
1466
1467 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001468 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1469 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001470 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001471 | 4 | (ctrl->tRCD << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001472
Felix Held2bb3cdf2018-07-28 00:23:59 +02001473 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001474
Felix Held2bb3cdf2018-07-28 00:23:59 +02001475 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001476
1477 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001478 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1479 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1480 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1481 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001482
1483 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001484 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1485 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1486 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1487 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001488
1489 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001490 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1491 MCHBAR32(0x423c + 0x400 * channel) =
1492 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1493 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1494 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001495
Felix Held2bb3cdf2018-07-28 00:23:59 +02001496 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001497
1498 wait_428c(channel);
1499
1500 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001501 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1502 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1503 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1504 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001505
1506 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001507 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1508 MCHBAR32(0x4234 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001509 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001510 | 8 | (ctrl->CAS << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001511
Felix Held2bb3cdf2018-07-28 00:23:59 +02001512 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001513
Felix Held2bb3cdf2018-07-28 00:23:59 +02001514 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001515
1516 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001517 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1518 MCHBAR32(0x4238 + 0x400 * channel) =
1519 0x40011f4 | (max(ctrl->tRTP, 8) << 16);
1520 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1521 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001522
1523 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001524 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1525 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1526 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1527 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
1528 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001529 wait_428c(channel);
1530}
1531
1532static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1533{
1534 int timC;
1535 int statistics[NUM_LANES][MAX_TIMC + 1];
1536 int lane;
1537
1538 wait_428c(channel);
1539
1540 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001541 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1542 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1543 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1544 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
1545 MCHBAR32(0x4284 + 0x400 * channel) = 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;
1664 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001665
1666 wait_428c(channel);
1667 }
1668
1669 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1670 ctrl->timings[channel][slotrank].lanes[lane].falling =
1671 48;
1672 ctrl->timings[channel][slotrank].lanes[lane].rising =
1673 48;
1674 }
1675
1676 program_timings(ctrl, channel);
1677
1678 FOR_ALL_POPULATED_RANKS {
1679 wait_428c(channel);
1680 /* DRAM command MRS
1681 * write MR3 MPR enable
1682 * in this mode only RD and RDA are allowed
1683 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001684 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1685 MCHBAR32(0x4230 + 0x400 * channel) =
1686 0xc01 | (ctrl->tMOD << 16);
1687 MCHBAR32(0x4200 + 0x400 * channel) =
1688 (slotrank << 24) | 0x360004;
1689 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001690
1691 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001692 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1693 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1694 MCHBAR32(0x4204 + 0x400 * channel) =
1695 (slotrank << 24) | 0;
1696 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001697
1698 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001699 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1700 MCHBAR32(0x4238 + 0x400 * channel) =
1701 0x1001 | ((ctrl->CAS + 8) << 16);
1702 MCHBAR32(0x4208 + 0x400 * channel) =
1703 (slotrank << 24) | 0x60000;
1704 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001705
1706 /* DRAM command MRS
1707 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001708 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1709 MCHBAR32(0x423c + 0x400 * channel) =
1710 0xc01 | (ctrl->tMOD << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001711
Felix Held2bb3cdf2018-07-28 00:23:59 +02001712 MCHBAR32(0x420c + 0x400 * channel) =
1713 (slotrank << 24) | 0x360000;
1714 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001715
Felix Held2bb3cdf2018-07-28 00:23:59 +02001716 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001717 wait_428c(channel);
1718 }
1719 }
1720}
1721
1722static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1723{
1724 /* enable DQs on this slotrank */
1725 write_mrreg(ctrl, channel, slotrank, 1,
1726 0x80 | make_mr1(ctrl, slotrank, channel));
1727
1728 wait_428c(channel);
1729 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001730 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1731 MCHBAR32(0x4230 + 0x400 * channel) =
1732 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1733 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1734 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001735
1736 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001737 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1738 MCHBAR32(0x4234 + 0x400 * channel) =
1739 0x4000c01 | ((ctrl->CAS + 38) << 16);
1740 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1741 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001742
Felix Held2bb3cdf2018-07-28 00:23:59 +02001743 MCHBAR32(0x400 * channel + 0x4284) = 0x40001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001744 wait_428c(channel);
1745
1746 /* disable DQs on this slotrank */
1747 write_mrreg(ctrl, channel, slotrank, 1,
1748 0x1080 | make_mr1(ctrl, slotrank, channel));
1749}
1750
1751static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1752{
1753 int timB;
1754 int statistics[NUM_LANES][128];
1755 int lane;
1756
Felix Held2bb3cdf2018-07-28 00:23:59 +02001757 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001758
1759 for (timB = 0; timB < 128; timB++) {
1760 FOR_ALL_LANES {
1761 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1762 }
1763 program_timings(ctrl, channel);
1764
1765 test_timB(ctrl, channel, slotrank);
1766
1767 FOR_ALL_LANES {
1768 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001769 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001770 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1771 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001772 }
1773 }
1774 FOR_ALL_LANES {
1775 struct run rn = get_longest_zero_run(statistics[lane], 128);
1776 /* timC is a direct function of timB's 6 LSBs.
1777 * Some tests increments the value of timB by a small value,
1778 * which might cause the 6bit value to overflow, if it's close
1779 * to 0x3F. Increment the value by a small offset if it's likely
1780 * to overflow, to make sure it won't overflow while running
1781 * tests and bricks the system due to a non matching timC.
1782 *
1783 * TODO: find out why some tests (edge write discovery)
1784 * increment timB. */
1785 if ((rn.start & 0x3F) == 0x3E)
1786 rn.start += 2;
1787 else if ((rn.start & 0x3F) == 0x3F)
1788 rn.start += 1;
1789 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1790 if (rn.all) {
1791 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1792 channel, slotrank, lane);
1793 return MAKE_ERR;
1794 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001795 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1796 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001797 }
1798 return 0;
1799}
1800
1801static int get_timB_high_adjust(u64 val)
1802{
1803 int i;
1804
1805 /* good */
1806 if (val == 0xffffffffffffffffLL)
1807 return 0;
1808
1809 if (val >= 0xf000000000000000LL) {
1810 /* needs negative adjustment */
1811 for (i = 0; i < 8; i++)
1812 if (val << (8 * (7 - i) + 4))
1813 return -i;
1814 } else {
1815 /* needs positive adjustment */
1816 for (i = 0; i < 8; i++)
1817 if (val >> (8 * (7 - i) + 4))
1818 return i;
1819 }
1820 return 8;
1821}
1822
1823static void adjust_high_timB(ramctr_timing * ctrl)
1824{
1825 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001826 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001827 FOR_ALL_POPULATED_CHANNELS {
1828 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001829 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001830 }
1831 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1832
Felix Held2bb3cdf2018-07-28 00:23:59 +02001833 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001834
1835 wait_428c(channel);
1836
1837 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001838 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1839 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1840 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1841 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001842
1843 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001844 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1845 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1846 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1847 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001848
1849 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001850 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1851 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1852 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1853 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001854
1855 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001856 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1857 MCHBAR32(0x423c + 0x400 * channel) =
1858 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1859 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1860 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001861
Felix Held2bb3cdf2018-07-28 00:23:59 +02001862 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001863
1864 wait_428c(channel);
1865
1866 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001867 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1868 MCHBAR32(0x4230 + 0x400 * channel) =
1869 0xc01 | ((ctrl->tRP) << 16);
1870 MCHBAR32(0x4200 + 0x400 * channel) =
1871 (slotrank << 24) | 0x60400;
1872 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001873
1874 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001875 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1876 MCHBAR32(0x4234 + 0x400 * channel) =
1877 0xc01 | ((ctrl->tRCD) << 16);
1878 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1879 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001880
1881 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001882 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1883 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001884 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001885 ctrl->timings[channel][slotrank].val_4028) << 16);
1886 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1887 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001888
Felix Held2bb3cdf2018-07-28 00:23:59 +02001889 MCHBAR32(0x4284 + 0x400 * channel) = 0x80001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001890 wait_428c(channel);
1891 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001892 u64 res = MCHBAR32(lane_registers[lane] +
1893 0x100 * channel + 4);
1894 res |= ((u64) MCHBAR32(lane_registers[lane] +
1895 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001896 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1897 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1898 get_timB_high_adjust(res) * 64;
1899
1900 printram("High adjust %d:%016llx\n", lane, res);
1901 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1902 slotrank, lane, old,
1903 ctrl->timings[channel][slotrank].lanes[lane].
1904 timB);
1905 }
1906 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001907 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001908}
1909
1910static void write_op(ramctr_timing * ctrl, int channel)
1911{
1912 int slotrank;
1913
1914 wait_428c(channel);
1915
1916 /* choose an existing rank. */
1917 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1918
1919 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001920 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1921 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001922
Felix Held2bb3cdf2018-07-28 00:23:59 +02001923 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001924
Felix Held2bb3cdf2018-07-28 00:23:59 +02001925 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001926
Felix Held2bb3cdf2018-07-28 00:23:59 +02001927 MCHBAR32(0x4284 + 0x400 * channel) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001928 wait_428c(channel);
1929}
1930
1931/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1932 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1933 * the chips at different times with respect to command, address and
1934 * clock signals.
1935 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1936 * shift can be introduced.
1937 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1938 *
1939 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1940 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1941 * sampled value on the data lanes (DQs).
1942 */
1943int write_training(ramctr_timing * ctrl)
1944{
1945 int channel, slotrank, lane;
1946 int err;
1947
1948 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001949 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001950
1951 FOR_ALL_POPULATED_CHANNELS {
1952 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001953 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001954 }
1955
1956 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001957 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001958 FOR_ALL_POPULATED_CHANNELS {
1959 write_op(ctrl, channel);
1960 }
1961
1962 /* enable write leveling on all ranks
1963 * disable all DQ outputs
1964 * only NOP is allowed in this mode */
1965 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02001966 FOR_ALL_POPULATED_RANKS
1967 write_mrreg(ctrl, channel, slotrank, 1,
1968 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001969
Felix Held2bb3cdf2018-07-28 00:23:59 +02001970 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001971
1972 toggle_io_reset();
1973
1974 /* set any valid value for timB, it gets corrected later */
1975 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1976 err = discover_timB(ctrl, channel, slotrank);
1977 if (err)
1978 return err;
1979 }
1980
1981 /* disable write leveling on all ranks */
1982 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
1983 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02001984 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001985
Felix Held2bb3cdf2018-07-28 00:23:59 +02001986 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001987
1988 FOR_ALL_POPULATED_CHANNELS
1989 wait_428c(channel);
1990
1991 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02001992 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001993
1994 FOR_ALL_POPULATED_CHANNELS {
Felix Heldb802c072018-07-29 21:46:19 +02001995 volatile u32 tmp;
Felix Held2463aa92018-07-29 21:37:55 +02001996 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001997 tmp = MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001998 wait_428c(channel);
1999
2000 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002001 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2002 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2003 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2004 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002005
Felix Held2bb3cdf2018-07-28 00:23:59 +02002006 MCHBAR32(0x4284 + 0x400 * channel) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002007 wait_428c(channel);
2008 }
2009
2010 toggle_io_reset();
2011
2012 printram("CPE\n");
2013 precharge(ctrl);
2014 printram("CPF\n");
2015
2016 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002017 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002018 }
2019
2020 FOR_ALL_POPULATED_CHANNELS {
2021 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002022 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002023 }
2024
2025 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2026 err = discover_timC(ctrl, channel, slotrank);
2027 if (err)
2028 return err;
2029 }
2030
2031 FOR_ALL_POPULATED_CHANNELS
2032 program_timings(ctrl, channel);
2033
2034 /* measure and adjust timB timings */
2035 adjust_high_timB(ctrl);
2036
2037 FOR_ALL_POPULATED_CHANNELS
2038 program_timings(ctrl, channel);
2039
2040 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002041 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002042 }
2043 return 0;
2044}
2045
2046static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2047{
2048 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2049 int timC_delta;
2050 int lanes_ok = 0;
2051 int ctr = 0;
2052 int lane;
2053
2054 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2055 FOR_ALL_LANES {
2056 ctrl->timings[channel][slotrank].lanes[lane].timC =
2057 saved_rt.lanes[lane].timC + timC_delta;
2058 }
2059 program_timings(ctrl, channel);
2060 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002061 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002062 }
2063
Felix Held2bb3cdf2018-07-28 00:23:59 +02002064 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002065
2066 wait_428c(channel);
2067 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002068 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2069 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002070 ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002071 | 8 | (ctrl->tRCD << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002072
Felix Held2bb3cdf2018-07-28 00:23:59 +02002073 MCHBAR32(0x4200 + 0x400 * channel) =
2074 (slotrank << 24) | ctr | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002075
Felix Held2bb3cdf2018-07-28 00:23:59 +02002076 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002077 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002078 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2079 MCHBAR32(0x4234 + 0x400 * channel) =
2080 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2081 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2082 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2083 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002084
2085 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002086 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2087 MCHBAR32(0x4238 + 0x400 * channel) =
2088 0x4001020 | (max(ctrl->tRTP, 8) << 16);
2089 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2090 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2091 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002092
2093 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002094 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2095 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2096 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2097 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002098
Felix Held2bb3cdf2018-07-28 00:23:59 +02002099 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002100 wait_428c(channel);
2101 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002102 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002103
2104 if (r32 == 0)
2105 lanes_ok |= 1 << lane;
2106 }
2107 ctr++;
2108 if (lanes_ok == ((1 << NUM_LANES) - 1))
2109 break;
2110 }
2111
2112 ctrl->timings[channel][slotrank] = saved_rt;
2113
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002114 return lanes_ok != ((1 << NUM_LANES) - 1);
2115}
2116
2117#include "raminit_patterns.h"
2118
2119static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2120{
2121 unsigned i, j;
2122 unsigned channel_offset =
2123 get_precedening_channels(ctrl, channel) * 0x40;
2124 unsigned channel_step = 0x40 * num_of_channels(ctrl);
2125
2126 if (patno) {
2127 u8 base8 = 0x80 >> ((patno - 1) % 8);
2128 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2129 for (i = 0; i < 32; i++) {
2130 for (j = 0; j < 16; j++) {
2131 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2132 if (invert[patno - 1][i] & (1 << (j / 2)))
2133 val = ~val;
2134 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2135 j * 4), val);
2136 }
2137 }
2138
2139 } else {
2140 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2141 for (j = 0; j < 16; j++)
2142 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2143 j * 4), pattern[i][j]);
2144 }
2145 sfence();
2146 }
2147}
2148
2149static void reprogram_320c(ramctr_timing * ctrl)
2150{
2151 int channel, slotrank;
2152
2153 FOR_ALL_POPULATED_CHANNELS {
2154 wait_428c(channel);
2155
2156 /* choose an existing rank. */
2157 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2158
2159 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002160 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2161 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002162
Felix Held2bb3cdf2018-07-28 00:23:59 +02002163 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002164
Felix Held2bb3cdf2018-07-28 00:23:59 +02002165 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002166
Felix Held2bb3cdf2018-07-28 00:23:59 +02002167 MCHBAR32(0x4284 + 0x400 * channel) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002168 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002169 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002170 }
2171
2172 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002173 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002174 FOR_ALL_POPULATED_CHANNELS {
2175 wait_428c(channel);
2176
2177 /* choose an existing rank. */
2178 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2179
2180 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002181 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2182 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002183
Felix Held2bb3cdf2018-07-28 00:23:59 +02002184 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002185
Felix Held2bb3cdf2018-07-28 00:23:59 +02002186 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002187
Felix Held2bb3cdf2018-07-28 00:23:59 +02002188 MCHBAR32(0x4284 + 0x400 * channel) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002189 wait_428c(channel);
2190 }
2191
2192 /* jedec reset */
2193 dram_jedecreset(ctrl);
2194 /* mrs commands. */
2195 dram_mrscommands(ctrl);
2196
2197 toggle_io_reset();
2198}
2199
2200#define MIN_C320C_LEN 13
2201
2202static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2203{
2204 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2205 int slotrank;
2206 int c320c;
2207 int stat[NUM_SLOTRANKS][256];
2208 int delta = 0;
2209
2210 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2211
2212 FOR_ALL_POPULATED_RANKS {
2213 saved_timings[channel][slotrank] =
2214 ctrl->timings[channel][slotrank];
2215 }
2216
2217 ctrl->cmd_stretch[channel] = cmd_stretch;
2218
2219 MCHBAR32(0x4004 + 0x400 * channel) =
2220 ctrl->tRRD
2221 | (ctrl->tRTP << 4)
2222 | (ctrl->tCKE << 8)
2223 | (ctrl->tWTR << 12)
2224 | (ctrl->tFAW << 16)
2225 | (ctrl->tWR << 24)
2226 | (ctrl->cmd_stretch[channel] << 30);
2227
2228 if (ctrl->cmd_stretch[channel] == 2)
2229 delta = 2;
2230 else if (ctrl->cmd_stretch[channel] == 0)
2231 delta = 4;
2232
2233 FOR_ALL_POPULATED_RANKS {
2234 ctrl->timings[channel][slotrank].val_4024 -= delta;
2235 }
2236
2237 for (c320c = -127; c320c <= 127; c320c++) {
2238 FOR_ALL_POPULATED_RANKS {
2239 ctrl->timings[channel][slotrank].val_320c = c320c;
2240 }
2241 program_timings(ctrl, channel);
2242 reprogram_320c(ctrl);
2243 FOR_ALL_POPULATED_RANKS {
2244 stat[slotrank][c320c + 127] =
2245 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002246 }
2247 }
2248 FOR_ALL_POPULATED_RANKS {
2249 struct run rn =
2250 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002251 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002252 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2253 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002254 if (rn.all || rn.length < MIN_C320C_LEN) {
2255 FOR_ALL_POPULATED_RANKS {
2256 ctrl->timings[channel][slotrank] =
2257 saved_timings[channel][slotrank];
2258 }
2259 return MAKE_ERR;
2260 }
2261 }
2262
2263 return 0;
2264}
2265
2266/* Adjust CMD phase shift and try multiple command rates.
2267 * A command rate of 2T doubles the time needed for address and
2268 * command decode. */
2269int command_training(ramctr_timing *ctrl)
2270{
2271 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002272
2273 FOR_ALL_POPULATED_CHANNELS {
2274 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002275 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002276 }
2277
2278 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002279 int cmdrate, err;
2280
2281 /*
2282 * Dual DIMM per channel:
2283 * Issue: While c320c discovery seems to succeed raminit
2284 * will fail in write training.
2285 * Workaround: Skip 1T in dual DIMM mode, that's only
2286 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002287 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2288 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002289 *
2290 * Single DIMM per channel:
2291 * Try command rate 1T and 2T
2292 */
2293 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002294 if (ctrl->tCMD)
2295 /* XMP gives the CMD rate in clock ticks, not ns */
2296 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002297
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002298 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002299 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2300
2301 if (!err)
2302 break;
2303 }
2304
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002305 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002306 printk(BIOS_EMERG, "c320c discovery failed\n");
2307 return err;
2308 }
2309
2310 printram("Using CMD rate %uT on channel %u\n",
2311 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002312 }
2313
2314 FOR_ALL_POPULATED_CHANNELS
2315 program_timings(ctrl, channel);
2316
2317 reprogram_320c(ctrl);
2318 return 0;
2319}
2320
2321
2322static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2323 int *edges)
2324{
2325 int edge;
2326 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2327 int lane;
2328
2329 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2330 FOR_ALL_LANES {
2331 ctrl->timings[channel][slotrank].lanes[lane].rising =
2332 edge;
2333 ctrl->timings[channel][slotrank].lanes[lane].falling =
2334 edge;
2335 }
2336 program_timings(ctrl, channel);
2337
2338 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002339 volatile u32 tmp;
2340 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
2341 tmp = MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002342 }
2343
2344 wait_428c(channel);
2345 /* DRAM command MRS
2346 * write MR3 MPR enable
2347 * in this mode only RD and RDA are allowed
2348 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002349 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002350 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002351 MCHBAR32(0x4200 + 0x400 * channel) =
2352 (slotrank << 24) | 0x360004;
2353 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002354
2355 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002356 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2357 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2358 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2359 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002360
2361 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002362 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2363 MCHBAR32(0x4238 + 0x400 * channel) =
2364 0x1001 | ((ctrl->CAS + 8) << 16);
2365 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2366 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002367
2368 /* DRAM command MRS
2369 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002370 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2371 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2372 MCHBAR32(0x420c + 0x400 * channel) =
2373 (slotrank << 24) | 0x360000;
2374 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002375
Felix Held2bb3cdf2018-07-28 00:23:59 +02002376 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002377
2378 wait_428c(channel);
2379
2380 FOR_ALL_LANES {
2381 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002382 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002383 }
2384 }
2385 FOR_ALL_LANES {
2386 struct run rn =
2387 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2388 edges[lane] = rn.middle;
2389 if (rn.all) {
2390 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2391 channel, slotrank, lane);
2392 return MAKE_ERR;
2393 }
2394 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2395 lane, edges[lane]);
2396 }
2397 return 0;
2398}
2399
2400int discover_edges(ramctr_timing *ctrl)
2401{
2402 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2403 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2404 int channel, slotrank, lane;
2405 int err;
2406
Felix Held2bb3cdf2018-07-28 00:23:59 +02002407 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002408
2409 toggle_io_reset();
2410
2411 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002412 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002413 }
2414
2415 FOR_ALL_POPULATED_CHANNELS {
2416 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002417 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002418 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002419 volatile u32 tmp;
2420 tmp = MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002421 }
2422
2423 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2424 ctrl->timings[channel][slotrank].lanes[lane].falling =
2425 16;
2426 ctrl->timings[channel][slotrank].lanes[lane].rising =
2427 16;
2428 }
2429
2430 program_timings(ctrl, channel);
2431
2432 FOR_ALL_POPULATED_RANKS {
2433 wait_428c(channel);
2434
2435 /* DRAM command MRS
2436 * MR3 enable MPR
2437 * write MR3 MPR enable
2438 * in this mode only RD and RDA are allowed
2439 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002440 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2441 MCHBAR32(0x4230 + 0x400 * channel) =
2442 0xc01 | (ctrl->tMOD << 16);
2443 MCHBAR32(0x4200 + 0x400 * channel) =
2444 (slotrank << 24) | 0x360004;
2445 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002446
2447 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002448 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2449 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2450 MCHBAR32(0x4204 + 0x400 * channel) =
2451 (slotrank << 24) | 0;
2452 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002453
2454 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002455 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2456 MCHBAR32(0x4238 + 0x400 * channel) =
2457 0x1001 | ((ctrl->CAS + 8) << 16);
2458 MCHBAR32(0x4208 + 0x400 * channel) =
2459 (slotrank << 24) | 0x60000;
2460 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002461
2462 /* DRAM command MRS
2463 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002464 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2465 MCHBAR32(0x423c + 0x400 * channel) =
2466 0xc01 | (ctrl->tMOD << 16);
2467 MCHBAR32(0x420c + 0x400 * channel) =
2468 (slotrank << 24) | 0x360000;
2469 MCHBAR32(0x421c + 0x400 * channel) = 0;
2470 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002471
2472 wait_428c(channel);
2473 }
2474
2475 /* XXX: check any measured value ? */
2476
2477 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2478 ctrl->timings[channel][slotrank].lanes[lane].falling =
2479 48;
2480 ctrl->timings[channel][slotrank].lanes[lane].rising =
2481 48;
2482 }
2483
2484 program_timings(ctrl, channel);
2485
2486 FOR_ALL_POPULATED_RANKS {
2487 wait_428c(channel);
2488
2489 /* DRAM command MRS
2490 * MR3 enable MPR
2491 * write MR3 MPR enable
2492 * in this mode only RD and RDA are allowed
2493 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002494 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2495 MCHBAR32(0x4230 + 0x400 * channel) =
2496 0xc01 | (ctrl->tMOD << 16);
2497 MCHBAR32(0x4200 + 0x400 * channel) =
2498 (slotrank << 24) | 0x360004;
2499 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002500
2501 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002502 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2503 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2504 MCHBAR32(0x4204 + 0x400 * channel) =
2505 (slotrank << 24) | 0;
2506 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002507
2508 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002509 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2510 MCHBAR32(0x4238 + 0x400 * channel) =
2511 0x1001 | ((ctrl->CAS + 8) << 16);
2512 MCHBAR32(0x4208 + 0x400 * channel) =
2513 (slotrank << 24) | 0x60000;
2514 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002515
2516 /* DRAM command MRS
2517 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002518 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2519 MCHBAR32(0x423c + 0x400 * channel) =
2520 0xc01 | (ctrl->tMOD << 16);
2521 MCHBAR32(0x420c + 0x400 * channel) =
2522 (slotrank << 24) | 0x360000;
2523 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002524
Felix Held2bb3cdf2018-07-28 00:23:59 +02002525 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002526 wait_428c(channel);
2527 }
2528
2529 /* XXX: check any measured value ? */
2530
2531 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002532 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2533 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2534 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002535 }
2536
2537 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002538 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002539 }
2540
2541 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002542 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002543 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2544
2545 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2546 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002547 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002548 if (err)
2549 return err;
2550 }
2551
Felix Held2bb3cdf2018-07-28 00:23:59 +02002552 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002553 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2554
2555 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2556 err = discover_edges_real(ctrl, channel, slotrank,
2557 rising_edges[channel][slotrank]);
2558 if (err)
2559 return err;
2560 }
2561
Felix Held2bb3cdf2018-07-28 00:23:59 +02002562 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002563
2564 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2565 ctrl->timings[channel][slotrank].lanes[lane].falling =
2566 falling_edges[channel][slotrank][lane];
2567 ctrl->timings[channel][slotrank].lanes[lane].rising =
2568 rising_edges[channel][slotrank][lane];
2569 }
2570
2571 FOR_ALL_POPULATED_CHANNELS {
2572 program_timings(ctrl, channel);
2573 }
2574
2575 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002576 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002577 }
2578 return 0;
2579}
2580
2581static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2582 int slotrank, int *edges)
2583{
2584 int edge;
2585 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2586 int statistics[MAX_EDGE_TIMING + 1];
2587 const int reg3000b24[] = { 0, 0xc, 0x2c };
2588 int lane, i;
2589 int lower[NUM_LANES];
2590 int upper[NUM_LANES];
2591 int pat;
2592
2593 FOR_ALL_LANES {
2594 lower[lane] = 0;
2595 upper[lane] = MAX_EDGE_TIMING;
2596 }
2597
2598 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002599 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002600 printram("[%x] = 0x%08x\n",
2601 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2602 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2603 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002604 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002605 printram("using pattern %d\n", pat);
2606 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2607 FOR_ALL_LANES {
2608 ctrl->timings[channel][slotrank].lanes[lane].
2609 rising = edge;
2610 ctrl->timings[channel][slotrank].lanes[lane].
2611 falling = edge;
2612 }
2613 program_timings(ctrl, channel);
2614
2615 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002616 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002617 MCHBAR32(0x4340 + 0x400 * channel +
2618 4 * lane) = 0;
2619 tmp = MCHBAR32(0x400 * channel +
2620 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002621 }
2622 wait_428c(channel);
2623
2624 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002625 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2626 MCHBAR32(0x4230 + 0x400 * channel) =
2627 0x4 | (ctrl->tRCD << 16) |
2628 (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
2629 << 10);
2630 MCHBAR32(0x4200 + 0x400 * channel) =
2631 (slotrank << 24) | 0x60000;
2632 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002633
2634 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002635 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2636 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2637 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2638 MCHBAR32(0x4204 + 0x400 * channel) =
2639 slotrank << 24;
2640 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002641
2642 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002643 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2644 MCHBAR32(0x4238 + 0x400 * channel) =
2645 0x4005020 | (max(ctrl->tRTP, 8) << 16);
2646 MCHBAR32(0x4208 + 0x400 * channel) =
2647 slotrank << 24;
2648 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002649
2650 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002651 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2652 MCHBAR32(0x423c + 0x400 * channel) =
2653 0xc01 | (ctrl->tRP << 16);
2654 MCHBAR32(0x420c + 0x400 * channel) =
2655 (slotrank << 24) | 0x60400;
2656 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002657
Felix Held2bb3cdf2018-07-28 00:23:59 +02002658 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002659 wait_428c(channel);
2660 FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002661 volatile u32 tmp;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002662 tmp = MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002663 0x400 * channel + lane * 4);
2664 }
2665
2666 raw_statistics[edge] =
2667 MCHBAR32(0x436c + 0x400 * channel);
2668 }
2669 FOR_ALL_LANES {
2670 struct run rn;
2671 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2672 statistics[edge] =
2673 ! !(raw_statistics[edge] & (1 << lane));
2674 rn = get_longest_zero_run(statistics,
2675 MAX_EDGE_TIMING + 1);
2676 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2677 channel, slotrank, i, rn.start, rn.middle,
2678 rn.end, rn.start + ctrl->edge_offset[i],
2679 rn.end - ctrl->edge_offset[i]);
2680 lower[lane] =
2681 max(rn.start + ctrl->edge_offset[i], lower[lane]);
2682 upper[lane] =
2683 min(rn.end - ctrl->edge_offset[i], upper[lane]);
2684 edges[lane] = (lower[lane] + upper[lane]) / 2;
2685 if (rn.all || (lower[lane] > upper[lane])) {
2686 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2687 channel, slotrank, lane);
2688 return MAKE_ERR;
2689 }
2690 }
2691 }
2692 }
2693
Felix Held2bb3cdf2018-07-28 00:23:59 +02002694 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002695 printram("CPA\n");
2696 return 0;
2697}
2698
2699int discover_edges_write(ramctr_timing *ctrl)
2700{
2701 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2702 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2703 int channel, slotrank, lane;
2704 int err;
2705
2706 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002707 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002708 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2709
2710 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2711 err = discover_edges_write_real(ctrl, channel, slotrank,
2712 falling_edges[channel][slotrank]);
2713 if (err)
2714 return err;
2715 }
2716
Felix Held2bb3cdf2018-07-28 00:23:59 +02002717 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002718 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2719
2720 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2721 err = discover_edges_write_real(ctrl, channel, slotrank,
2722 rising_edges[channel][slotrank]);
2723 if (err)
2724 return err;
2725 }
2726
Felix Held2bb3cdf2018-07-28 00:23:59 +02002727 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002728
2729 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2730 ctrl->timings[channel][slotrank].lanes[lane].falling =
2731 falling_edges[channel][slotrank][lane];
2732 ctrl->timings[channel][slotrank].lanes[lane].rising =
2733 rising_edges[channel][slotrank][lane];
2734 }
2735
2736 FOR_ALL_POPULATED_CHANNELS
2737 program_timings(ctrl, channel);
2738
2739 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002740 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002741 }
2742 return 0;
2743}
2744
2745static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2746{
2747 wait_428c(channel);
2748 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002749 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2750 MCHBAR32(0x4230 + 0x400 * channel) =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002751 (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002752 << 10) | (ctrl->tRCD << 16) | 4;
2753 MCHBAR32(0x4200 + 0x400 * channel) =
2754 (slotrank << 24) | 0x60000;
2755 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002756
2757 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002758 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2759 MCHBAR32(0x4234 + 0x400 * channel) =
2760 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2761 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2762 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002763
2764 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002765 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2766 MCHBAR32(0x4238 + 0x400 * channel) =
2767 0x40011e0 | (max(ctrl->tRTP, 8) << 16);
2768 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2769 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002770
2771 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002772 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2773 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2774 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2775 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002776
Felix Held2bb3cdf2018-07-28 00:23:59 +02002777 MCHBAR32(0x4284 + 0x400 * channel) = 0xc0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002778 wait_428c(channel);
2779}
2780
2781int discover_timC_write(ramctr_timing *ctrl)
2782{
2783 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2784 int i, pat;
2785
2786 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2787 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2788 int channel, slotrank, lane;
2789
2790 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2791 lower[channel][slotrank][lane] = 0;
2792 upper[channel][slotrank][lane] = MAX_TIMC;
2793 }
2794
Felix Held2bb3cdf2018-07-28 00:23:59 +02002795 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002796 printram("discover timC write:\n");
2797
2798 for (i = 0; i < 3; i++)
2799 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002800 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2801 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002802 udelay(2);
2803 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2804 FOR_ALL_POPULATED_RANKS {
2805 int timC;
2806 u32 raw_statistics[MAX_TIMC + 1];
2807 int statistics[MAX_TIMC + 1];
2808
2809 /* Make sure rn.start < rn.end */
2810 statistics[MAX_TIMC] = 1;
2811
2812 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002813 MCHBAR32(0x4288 + 0x400 * channel) =
2814 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002815 for (timC = 0; timC < MAX_TIMC; timC++) {
2816 FOR_ALL_LANES
2817 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2818 program_timings(ctrl, channel);
2819
2820 test_timC_write (ctrl, channel, slotrank);
2821
2822 raw_statistics[timC] =
2823 MCHBAR32(0x436c + 0x400 * channel);
2824 }
2825 FOR_ALL_LANES {
2826 struct run rn;
2827 for (timC = 0; timC < MAX_TIMC; timC++)
2828 statistics[timC] =
2829 !!(raw_statistics[timC] &
2830 (1 << lane));
2831
2832 rn = get_longest_zero_run(statistics,
2833 MAX_TIMC + 1);
2834 if (rn.all) {
2835 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2836 channel, slotrank, lane);
2837 return MAKE_ERR;
2838 }
2839 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2840 channel, slotrank, i, rn.start,
2841 rn.middle, rn.end,
2842 rn.start + ctrl->timC_offset[i],
2843 rn.end - ctrl->timC_offset[i]);
2844 lower[channel][slotrank][lane] =
2845 max(rn.start + ctrl->timC_offset[i],
2846 lower[channel][slotrank][lane]);
2847 upper[channel][slotrank][lane] =
2848 min(rn.end - ctrl->timC_offset[i],
2849 upper[channel][slotrank][lane]);
2850
2851 }
2852 }
2853 }
2854 }
2855
2856 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002857 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002858 udelay(2);
2859 }
2860
Felix Held2bb3cdf2018-07-28 00:23:59 +02002861 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002862
2863 printram("CPB\n");
2864
2865 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2866 printram("timC %d, %d, %d: %x\n", channel,
2867 slotrank, lane,
2868 (lower[channel][slotrank][lane] +
2869 upper[channel][slotrank][lane]) / 2);
2870 ctrl->timings[channel][slotrank].lanes[lane].timC =
2871 (lower[channel][slotrank][lane] +
2872 upper[channel][slotrank][lane]) / 2;
2873 }
2874 FOR_ALL_POPULATED_CHANNELS {
2875 program_timings(ctrl, channel);
2876 }
2877 return 0;
2878}
2879
2880void normalize_training(ramctr_timing * ctrl)
2881{
2882 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002883 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002884
2885 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2886 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002887 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002888 FOR_ALL_LANES mat =
2889 max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002890 printram("normalize %d, %d, %d: mat %d\n",
2891 channel, slotrank, lane, mat);
2892
2893 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2894 printram("normalize %d, %d, %d: delta %d\n",
2895 channel, slotrank, lane, delta);
2896
2897 ctrl->timings[channel][slotrank].val_4024 += delta;
2898 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002899 }
2900
2901 FOR_ALL_POPULATED_CHANNELS {
2902 program_timings(ctrl, channel);
2903 }
2904}
2905
2906void write_controller_mr(ramctr_timing * ctrl)
2907{
2908 int channel, slotrank;
2909
2910 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002911 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2912 make_mr0(ctrl, slotrank);
2913 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2914 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002915 }
2916}
2917
2918int channel_test(ramctr_timing *ctrl)
2919{
2920 int channel, slotrank, lane;
2921
2922 slotrank = 0;
2923 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002924 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002925 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2926 channel);
2927 return MAKE_ERR;
2928 }
2929 FOR_ALL_POPULATED_CHANNELS {
2930 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2931
Felix Held2bb3cdf2018-07-28 00:23:59 +02002932 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002933 }
2934
2935 for (slotrank = 0; slotrank < 4; slotrank++)
2936 FOR_ALL_CHANNELS
2937 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2938 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002939 MCHBAR32(0x4f40 + 4 * lane) = 0;
2940 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002941 }
2942 wait_428c(channel);
2943 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002944 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2945 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2946 MCHBAR32(0x4200 + (channel << 10)) =
2947 0x00060000 | (slotrank << 24);
2948 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002949 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002950 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2951 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2952 MCHBAR32(0x4204 + (channel << 10)) =
2953 0x00000000 | (slotrank << 24);
2954 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002955 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002956 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
2957 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
2958 MCHBAR32(0x4208 + (channel << 10)) =
2959 0x00000000 | (slotrank << 24);
2960 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002961 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002962 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
2963 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
2964 MCHBAR32(0x420c + (channel << 10)) =
2965 0x00060400 | (slotrank << 24);
2966 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
2967 MCHBAR32(0x4284 + (channel << 10)) = 0x000c0001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002968 wait_428c(channel);
2969 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02002970 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002971 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
2972 channel, slotrank, lane);
2973 return MAKE_ERR;
2974 }
2975 }
2976 return 0;
2977}
2978
2979void set_scrambling_seed(ramctr_timing * ctrl)
2980{
2981 int channel;
2982
2983 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
2984 I don't think so. */
2985 static u32 seeds[NUM_CHANNELS][3] = {
2986 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
2987 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
2988 };
2989 FOR_ALL_POPULATED_CHANNELS {
2990 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02002991 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
2992 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
2993 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002994 }
2995}
2996
2997void set_4f8c(void)
2998{
2999 struct cpuid_result cpures;
3000 u32 cpu;
3001
3002 cpures = cpuid(1);
3003 cpu = (cpures.eax);
3004 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3005 MCHBAR32(0x4f8c) = 0x141D1519;
3006 } else {
3007 MCHBAR32(0x4f8c) = 0x551D1519;
3008 }
3009}
3010
3011void prepare_training(ramctr_timing * ctrl)
3012{
3013 int channel;
3014
3015 FOR_ALL_POPULATED_CHANNELS {
3016 // Always drive command bus
3017 MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000;
3018 }
3019
3020 udelay(1);
3021
3022 FOR_ALL_POPULATED_CHANNELS {
3023 wait_428c(channel);
3024 }
3025}
3026
3027void set_4008c(ramctr_timing * ctrl)
3028{
3029 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003030
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003031 FOR_ALL_POPULATED_CHANNELS {
3032 u32 b20, b4_8_12;
3033 int min_320c = 10000;
3034 int max_320c = -10000;
3035
3036 FOR_ALL_POPULATED_RANKS {
3037 max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c);
3038 min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c);
3039 }
3040
3041 if (max_320c - min_320c > 51)
3042 b20 = 0;
3043 else
3044 b20 = ctrl->ref_card_offset[channel];
3045
3046 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3047 b4_8_12 = 0x3330;
3048 else
3049 b4_8_12 = 0x2220;
3050
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003051 dram_odt_stretch(ctrl, channel);
3052
Felix Held2bb3cdf2018-07-28 00:23:59 +02003053 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003054 0x0a000000 | (b20 << 20) |
3055 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003056 }
3057}
3058
3059void set_42a0(ramctr_timing * ctrl)
3060{
3061 int channel;
3062 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003063 MCHBAR32(0x42a0 + 0x400 * channel) =
3064 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003065 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003066 }
3067}
3068
3069static int encode_5d10(int ns)
3070{
3071 return (ns + 499) / 500;
3072}
3073
3074/* FIXME: values in this function should be hardware revision-dependent. */
3075void final_registers(ramctr_timing * ctrl)
3076{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003077 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3078
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003079 int channel;
3080 int t1_cycles = 0, t1_ns = 0, t2_ns;
3081 int t3_ns;
3082 u32 r32;
3083
Felix Held2bb3cdf2018-07-28 00:23:59 +02003084 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003085
Felix Held2463aa92018-07-29 21:37:55 +02003086 MCHBAR32_AND_OR(0x400c, 0xFFFFCFFF, 0x1000);
3087 MCHBAR32_AND_OR(0x440c, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003088
Patrick Rudolph74203de2017-11-20 11:57:01 +01003089 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003090 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3091 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3092 else
3093 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3094 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3095
Felix Held2bb3cdf2018-07-28 00:23:59 +02003096 MCHBAR32(0x4380) = 0x00000aaa; // OK
3097 MCHBAR32(0x4780) = 0x00000aaa; // OK
3098 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3099 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003100
3101 FOR_ALL_CHANNELS {
3102 switch (ctrl->rankmap[channel]) {
3103 /* Unpopulated channel. */
3104 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003105 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003106 break;
3107 /* Only single-ranked dimms. */
3108 case 1:
3109 case 4:
3110 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003111 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003112 break;
3113 /* Dual-ranked dimms present. */
3114 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003115 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003116 break;
3117 }
3118 }
3119
Felix Held2bb3cdf2018-07-28 00:23:59 +02003120 MCHBAR32(0x5880) = 0xca9171e5;
Felix Held2463aa92018-07-29 21:37:55 +02003121 MCHBAR32_AND_OR(0x5888, ~0xffffff, 0xe4d5d0);
3122 MCHBAR32_AND(0x58a8, ~0x1f);
3123 MCHBAR32_AND_OR(0x4294, ~0x30000, 1 << 16);
3124 MCHBAR32_AND_OR(0x4694, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003125
Felix Held2463aa92018-07-29 21:37:55 +02003126 MCHBAR32(0x5030) |= 1;
3127 MCHBAR32(0x5030) |= 0x80;
3128 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003129
3130 /* Find a populated channel. */
3131 FOR_ALL_POPULATED_CHANNELS
3132 break;
3133
Felix Held2bb3cdf2018-07-28 00:23:59 +02003134 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3135 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003136 if (r32 & 0x20000)
3137 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003138 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003139 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3140 if (!(r32 & 0x20000))
3141 t1_ns += 500;
3142
Felix Held2bb3cdf2018-07-28 00:23:59 +02003143 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3144 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003145 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003146 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3147 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003148 }
3149 else
3150 {
3151 t3_ns = 500;
3152 }
3153 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3154 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003155 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3156 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003157 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003158 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003159}
3160
3161void restore_timings(ramctr_timing * ctrl)
3162{
3163 int channel, slotrank, lane;
3164
3165 FOR_ALL_POPULATED_CHANNELS
3166 MCHBAR32(0x4004 + 0x400 * channel) =
3167 ctrl->tRRD
3168 | (ctrl->tRTP << 4)
3169 | (ctrl->tCKE << 8)
3170 | (ctrl->tWTR << 12)
3171 | (ctrl->tFAW << 16)
3172 | (ctrl->tWR << 24)
3173 | (ctrl->cmd_stretch[channel] << 30);
3174
3175 udelay(1);
3176
3177 FOR_ALL_POPULATED_CHANNELS {
3178 wait_428c(channel);
3179 }
3180
3181 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003182 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003183 }
3184
3185 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003186 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003187
3188 FOR_ALL_POPULATED_CHANNELS {
3189 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003190 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003191 }
3192
3193 printram("CPE\n");
3194
Felix Held2bb3cdf2018-07-28 00:23:59 +02003195 MCHBAR32(0x3400) = 0;
3196 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003197
3198 printram("CP5b\n");
3199
3200 FOR_ALL_POPULATED_CHANNELS {
3201 program_timings(ctrl, channel);
3202 }
3203
3204 u32 reg, addr;
3205
3206 while (!(MCHBAR32(0x5084) & 0x10000));
3207 do {
3208 reg = MCHBAR32(0x428c);
3209 } while ((reg & 0x14) == 0);
3210
3211 // Set state of memory controller
3212 MCHBAR32(0x5030) = 0x116;
3213 MCHBAR32(0x4ea0) = 0;
3214
3215 // Wait 500us
3216 udelay(500);
3217
3218 FOR_ALL_CHANNELS {
3219 // Set valid rank CKE
3220 reg = 0;
3221 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3222 addr = 0x400 * channel + 0x42a0;
3223 MCHBAR32(addr) = reg;
3224
3225 // Wait 10ns for ranks to settle
3226 //udelay(0.01);
3227
3228 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3229 MCHBAR32(addr) = reg;
3230
3231 // Write reset using a NOP
3232 write_reset(ctrl);
3233 }
3234
3235 /* mrs commands. */
3236 dram_mrscommands(ctrl);
3237
3238 printram("CP5c\n");
3239
Felix Held2bb3cdf2018-07-28 00:23:59 +02003240 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003241
3242 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003243 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003244 udelay(2);
3245 }
3246
Felix Held2bb3cdf2018-07-28 00:23:59 +02003247 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003248}