blob: 3cc9d298d7ed9e2e1dd63adeb4c9e48cbb6b56fc [file] [log] [blame]
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
5 * Copyright (C) 2014 Vladimir Serbinenko <phcoder@gmail.com>
6 * Copyright (C) 2016 Patrick Rudolph <siro@das-labor.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
Elyes HAOUASf97c1c92019-12-03 18:22:06 +010018#include <commonlib/helpers.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010019#include <console/console.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010020#include <string.h>
Subrata Banik53b08c32018-12-10 14:11:35 +053021#include <arch/cpu.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020022#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020023#include <device/pci_ops.h>
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010024#include <northbridge/intel/sandybridge/chip.h>
25#include <device/pci_def.h>
26#include <delay.h>
Elyes HAOUAS1d3b3c32019-05-04 08:12:42 +020027
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010028#include "raminit_native.h"
29#include "raminit_common.h"
30#include "sandybridge.h"
31
32/* FIXME: no ECC support. */
33/* FIXME: no support for 3-channel chipsets. */
34
35/*
36 * Register description:
37 * Intel provides a command queue of depth four.
38 * Every command is configured by using multiple registers.
39 * On executing the command queue you have to provide the depth used.
40 *
41 * Known registers:
42 * Channel X = [0, 1]
43 * Command queue index Y = [0, 1, 2, 3]
44 *
45 * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register
46 * Controls the DRAM command signals
47 * Bit 0: !RAS
48 * Bit 1: !CAS
49 * Bit 2: !WE
50 *
51 * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register
52 * Controls the address, bank address and slotrank signals
53 * Bit 0-15 : Address
54 * Bit 20-22: Bank Address
55 * Bit 24-25: slotrank
56 *
57 * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register
58 * Controls the idle time after issuing this DRAM command
59 * Bit 16-32: number of clock-cylces to idle
60 *
61 * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue
62 * Starts to execute all queued commands
63 * Bit 0 : start DRAM command execution
Felix Held9cf1dd22018-07-31 14:52:40 +020064 * Bit 18-19 : number of queued commands - 1
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010065 */
66
Felix Held9cf1dd22018-07-31 14:52:40 +020067#define RUN_QUEUE_4284(x) ((((x) - 1) << 18) | 1) // 0 <= x < 4
68
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010069static void sfence(void)
70{
71 asm volatile ("sfence");
72}
73
74static void toggle_io_reset(void) {
75 /* toggle IO reset bit */
Felix Held2bb3cdf2018-07-28 00:23:59 +020076 u32 r32 = MCHBAR32(0x5030);
77 MCHBAR32(0x5030) = r32 | 0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010078 udelay(1);
Felix Held2bb3cdf2018-07-28 00:23:59 +020079 MCHBAR32(0x5030) = r32 & ~0x20;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010080 udelay(1);
81}
82
83static u32 get_XOVER_CLK(u8 rankmap)
84{
85 return rankmap << 24;
86}
87
88static u32 get_XOVER_CMD(u8 rankmap)
89{
90 u32 reg;
91
92 // enable xover cmd
93 reg = 0x4000;
94
95 // enable xover ctl
96 if (rankmap & 0x3)
97 reg |= 0x20000;
98
99 if (rankmap & 0xc)
100 reg |= 0x4000000;
101
102 return reg;
103}
104
105/* CAS write latency. To be programmed in MR2.
106 * See DDR3 SPEC for MR2 documentation. */
107u8 get_CWL(u32 tCK)
108{
109 /* Get CWL based on tCK using the following rule: */
110 switch (tCK) {
111 case TCK_1333MHZ:
112 return 12;
113 case TCK_1200MHZ:
114 case TCK_1100MHZ:
115 return 11;
116 case TCK_1066MHZ:
117 case TCK_1000MHZ:
118 return 10;
119 case TCK_933MHZ:
120 case TCK_900MHZ:
121 return 9;
122 case TCK_800MHZ:
123 case TCK_700MHZ:
124 return 8;
125 case TCK_666MHZ:
126 return 7;
127 case TCK_533MHZ:
128 return 6;
129 default:
130 return 5;
131 }
132}
133
134void dram_find_common_params(ramctr_timing *ctrl)
135{
136 size_t valid_dimms;
137 int channel, slot;
138 dimm_info *dimms = &ctrl->info;
139
140 ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1;
141 valid_dimms = 0;
142 FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) {
143 const dimm_attr *dimm = &dimms->dimm[channel][slot];
144 if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3)
145 continue;
146 valid_dimms++;
147
148 /* Find all possible CAS combinations */
149 ctrl->cas_supported &= dimm->cas_supported;
150
151 /* Find the smallest common latencies supported by all DIMMs */
152 ctrl->tCK = MAX(ctrl->tCK, dimm->tCK);
153 ctrl->tAA = MAX(ctrl->tAA, dimm->tAA);
154 ctrl->tWR = MAX(ctrl->tWR, dimm->tWR);
155 ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD);
156 ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD);
157 ctrl->tRP = MAX(ctrl->tRP, dimm->tRP);
158 ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS);
159 ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC);
160 ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR);
161 ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP);
162 ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW);
Dan Elkoubydabebc32018-04-13 18:47:10 +0300163 ctrl->tCWL = MAX(ctrl->tCWL, dimm->tCWL);
164 ctrl->tCMD = MAX(ctrl->tCMD, dimm->tCMD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100165 }
166
167 if (!ctrl->cas_supported)
168 die("Unsupported DIMM combination. "
169 "DIMMS do not support common CAS latency");
170 if (!valid_dimms)
171 die("No valid DIMMs found");
172}
173
174void dram_xover(ramctr_timing * ctrl)
175{
176 u32 reg;
177 int channel;
178
179 FOR_ALL_CHANNELS {
180 // enable xover clk
181 reg = get_XOVER_CLK(ctrl->rankmap[channel]);
182 printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14,
183 reg);
184 MCHBAR32(channel * 0x100 + 0xc14) = reg;
185
186 // enable xover ctl & xover cmd
187 reg = get_XOVER_CMD(ctrl->rankmap[channel]);
188 printram("XOVER CMD [%x] = %x\n", 0x100 * channel + 0x320c,
189 reg);
190 MCHBAR32(0x100 * channel + 0x320c) = reg;
191 }
192}
193
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100194static void dram_odt_stretch(ramctr_timing *ctrl, int channel)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100195{
Iru Cai89af71c2018-08-16 16:46:27 +0800196 u32 addr, cpu, stretch;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100197
198 stretch = ctrl->ref_card_offset[channel];
199 /* ODT stretch: Delay ODT signal by stretch value.
200 * Useful for multi DIMM setups on the same channel. */
Subrata Banik53b08c32018-12-10 14:11:35 +0530201 cpu = cpu_get_cpuid();
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100202 if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) {
203 if (stretch == 2)
204 stretch = 3;
Iru Cai89af71c2018-08-16 16:46:27 +0800205 addr = 0x401c + 0x400 * channel;
206 MCHBAR32_AND_OR(addr, 0xffffc3ff,
Felix Held9fe248f2018-07-31 20:59:45 +0200207 (stretch << 12) | (stretch << 10));
Iru Cai89af71c2018-08-16 16:46:27 +0800208 printk(RAM_DEBUG, "OTHP Workaround [%x] = %x\n", addr,
209 MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100210 } else {
211 // OTHP
Iru Cai89af71c2018-08-16 16:46:27 +0800212 addr = 0x400c + 0x400 * channel;
213 MCHBAR32_AND_OR(addr, 0xfff0ffff,
Felix Held9fe248f2018-07-31 20:59:45 +0200214 (stretch << 16) | (stretch << 18));
Iru Cai89af71c2018-08-16 16:46:27 +0800215 printk(RAM_DEBUG, "OTHP [%x] = %x\n", addr, MCHBAR32(addr));
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100216 }
217}
218
219void dram_timing_regs(ramctr_timing *ctrl)
220{
221 u32 reg, addr, val32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100222 int channel;
223
224 FOR_ALL_CHANNELS {
225 // DBP
226 reg = 0;
227 reg |= ctrl->tRCD;
228 reg |= (ctrl->tRP << 4);
229 reg |= (ctrl->CAS << 8);
230 reg |= (ctrl->CWL << 12);
231 reg |= (ctrl->tRAS << 16);
Felix Helddee167e2019-12-30 17:30:16 +0100232 printram("DBP [%x] = %x\n", TC_DBP_C0 + 0x400 * channel, reg);
233 MCHBAR32(TC_DBP_C0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100234
235 // RAP
236 reg = 0;
237 reg |= ctrl->tRRD;
238 reg |= (ctrl->tRTP << 4);
239 reg |= (ctrl->tCKE << 8);
240 reg |= (ctrl->tWTR << 12);
241 reg |= (ctrl->tFAW << 16);
242 reg |= (ctrl->tWR << 24);
243 reg |= (3 << 30);
Felix Helddee167e2019-12-30 17:30:16 +0100244 printram("RAP [%x] = %x\n", TC_RAP_C0 + 0x400 * channel, reg);
245 MCHBAR32(TC_RAP_C0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100246
247 // OTHP
248 addr = 0x400 * channel + 0x400c;
249 reg = 0;
250 reg |= ctrl->tXPDLL;
251 reg |= (ctrl->tXP << 5);
252 reg |= (ctrl->tAONPD << 8);
253 reg |= 0xa0000;
254 printram("OTHP [%x] = %x\n", addr, reg);
255 MCHBAR32(addr) = reg;
256
257 MCHBAR32(0x400 * channel + 0x4014) = 0;
258
Felix Held9fe248f2018-07-31 20:59:45 +0200259 MCHBAR32_OR(addr, 0x00020000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100260
Patrick Rudolph19c3dad2016-11-26 11:37:45 +0100261 dram_odt_stretch(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100262
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100263 /*
Patrick Rudolphb009ac42018-07-25 15:27:50 +0200264 * TC-Refresh timing parameters
Patrick Rudolph5ee9bc12017-10-31 10:49:52 +0100265 * The tREFIx9 field should be programmed to minimum of
266 * 8.9*tREFI (to allow for possible delays from ZQ or
267 * isoc) and tRASmax (70us) divided by 1024.
268 */
269 val32 = MIN((ctrl->tREFI * 89) / 10, (70000 << 8) / ctrl->tCK);
270
271 reg = ((ctrl->tREFI & 0xffff) << 0) |
272 ((ctrl->tRFC & 0x1ff) << 16) |
273 (((val32 / 1024) & 0x7f) << 25);
Felix Helddee167e2019-12-30 17:30:16 +0100274 printram("REFI [%x] = %x\n", TC_RFTP_C0 + 0x400 * channel, reg);
275 MCHBAR32(TC_RFTP_C0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100276
Felix Helddee167e2019-12-30 17:30:16 +0100277 MCHBAR32_OR(TC_RFP_C0 + 0x400 * channel, 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100278
279 // SRFTP
280 reg = 0;
281 val32 = tDLLK;
282 reg = (reg & ~0xfff) | val32;
283 val32 = ctrl->tXSOffset;
284 reg = (reg & ~0xf000) | (val32 << 12);
285 val32 = tDLLK - ctrl->tXSOffset;
286 reg = (reg & ~0x3ff0000) | (val32 << 16);
287 val32 = ctrl->tMOD - 8;
288 reg = (reg & ~0xf0000000) | (val32 << 28);
289 printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4,
290 reg);
291 MCHBAR32(0x400 * channel + 0x42a4) = reg;
292 }
293}
294
295void dram_dimm_mapping(ramctr_timing *ctrl)
296{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100297 int channel;
298 dimm_info *info = &ctrl->info;
299
300 FOR_ALL_CHANNELS {
Nico Huberac4f2162017-10-01 18:14:43 +0200301 dimm_attr *dimmA, *dimmB;
302 u32 reg = 0;
303
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100304 if (info->dimm[channel][0].size_mb >=
305 info->dimm[channel][1].size_mb) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100306 dimmA = &info->dimm[channel][0];
307 dimmB = &info->dimm[channel][1];
Nico Huberac4f2162017-10-01 18:14:43 +0200308 reg |= 0 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100309 } else {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100310 dimmA = &info->dimm[channel][1];
311 dimmB = &info->dimm[channel][0];
Nico Huberac4f2162017-10-01 18:14:43 +0200312 reg |= 1 << 16;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100313 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100314
Nico Huberac4f2162017-10-01 18:14:43 +0200315 if (dimmA && (dimmA->ranks > 0)) {
316 reg |= dimmA->size_mb / 256;
317 reg |= (dimmA->ranks - 1) << 17;
318 reg |= (dimmA->width / 8 - 1) << 19;
319 }
320
321 if (dimmB && (dimmB->ranks > 0)) {
322 reg |= (dimmB->size_mb / 256) << 8;
323 reg |= (dimmB->ranks - 1) << 18;
324 reg |= (dimmB->width / 8 - 1) << 20;
325 }
326
327 reg |= 1 << 21; /* rank interleave */
328 reg |= 1 << 22; /* enhanced interleave */
329
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100330 if ((dimmA && (dimmA->ranks > 0))
331 || (dimmB && (dimmB->ranks > 0))) {
332 ctrl->mad_dimm[channel] = reg;
333 } else {
334 ctrl->mad_dimm[channel] = 0;
335 }
336 }
337}
338
339void dram_dimm_set_mapping(ramctr_timing * ctrl)
340{
341 int channel;
342 FOR_ALL_CHANNELS {
Felix Helddee167e2019-12-30 17:30:16 +0100343 MCHBAR32(MAD_DIMM_CH0 + channel * 4) = ctrl->mad_dimm[channel];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100344 }
345}
346
347void dram_zones(ramctr_timing * ctrl, int training)
348{
349 u32 reg, ch0size, ch1size;
350 u8 val;
351 reg = 0;
352 val = 0;
353 if (training) {
354 ch0size = ctrl->channel_size_mb[0] ? 256 : 0;
355 ch1size = ctrl->channel_size_mb[1] ? 256 : 0;
356 } else {
357 ch0size = ctrl->channel_size_mb[0];
358 ch1size = ctrl->channel_size_mb[1];
359 }
360
361 if (ch0size >= ch1size) {
362 reg = MCHBAR32(0x5014);
363 val = ch1size / 256;
364 reg = (reg & ~0xff000000) | val << 24;
365 reg = (reg & ~0xff0000) | (2 * val) << 16;
366 MCHBAR32(0x5014) = reg;
Felix Helddee167e2019-12-30 17:30:16 +0100367 MCHBAR32(MAD_CHNL) = 0x24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100368 } else {
369 reg = MCHBAR32(0x5014);
370 val = ch0size / 256;
371 reg = (reg & ~0xff000000) | val << 24;
372 reg = (reg & ~0xff0000) | (2 * val) << 16;
373 MCHBAR32(0x5014) = reg;
Felix Helddee167e2019-12-30 17:30:16 +0100374 MCHBAR32(MAD_CHNL) = 0x21;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100375 }
376}
377
378#define HOST_BRIDGE PCI_DEVFN(0, 0)
379#define DEFAULT_TCK TCK_800MHZ
380
381unsigned int get_mem_min_tck(void)
382{
383 u32 reg32;
384 u8 rev;
385 const struct device *dev;
386 const struct northbridge_intel_sandybridge_config *cfg = NULL;
387
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300388 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100389 if (dev)
390 cfg = dev->chip_info;
391
392 /* If this is zero, it just means devicetree.cb didn't set it */
393 if (!cfg || cfg->max_mem_clock_mhz == 0) {
Julius Wernercd49cce2019-03-05 16:53:33 -0800394 if (CONFIG(NATIVE_RAMINIT_IGNORE_MAX_MEM_FUSES))
Patrick Rudolphb794a692017-08-08 13:13:51 +0200395 return TCK_1333MHZ;
396
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100397 rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
398
399 if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
400 /* read Capabilities A Register DMFC bits */
401 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A);
402 reg32 &= 0x7;
403
404 switch (reg32) {
405 case 7: return TCK_533MHZ;
406 case 6: return TCK_666MHZ;
407 case 5: return TCK_800MHZ;
408 /* reserved: */
409 default:
410 break;
411 }
412 } else {
413 /* read Capabilities B Register DMFC bits */
414 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B);
415 reg32 = (reg32 >> 4) & 0x7;
416
417 switch (reg32) {
418 case 7: return TCK_533MHZ;
419 case 6: return TCK_666MHZ;
420 case 5: return TCK_800MHZ;
421 case 4: return TCK_933MHZ;
422 case 3: return TCK_1066MHZ;
423 case 2: return TCK_1200MHZ;
424 case 1: return TCK_1333MHZ;
425 /* reserved: */
426 default:
427 break;
428 }
429 }
430 return DEFAULT_TCK;
431 } else {
432 if (cfg->max_mem_clock_mhz >= 1066)
433 return TCK_1066MHZ;
434 else if (cfg->max_mem_clock_mhz >= 933)
435 return TCK_933MHZ;
436 else if (cfg->max_mem_clock_mhz >= 800)
437 return TCK_800MHZ;
438 else if (cfg->max_mem_clock_mhz >= 666)
439 return TCK_666MHZ;
440 else if (cfg->max_mem_clock_mhz >= 533)
441 return TCK_533MHZ;
442 else
443 return TCK_400MHZ;
444 }
445}
446
447#define DEFAULT_PCI_MMIO_SIZE 2048
448
449static unsigned int get_mmio_size(void)
450{
451 const struct device *dev;
452 const struct northbridge_intel_sandybridge_config *cfg = NULL;
453
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300454 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100455 if (dev)
456 cfg = dev->chip_info;
457
458 /* If this is zero, it just means devicetree.cb didn't set it */
459 if (!cfg || cfg->pci_mmio_size == 0)
460 return DEFAULT_PCI_MMIO_SIZE;
461 else
462 return cfg->pci_mmio_size;
463}
464
465void dram_memorymap(ramctr_timing * ctrl, int me_uma_size)
466{
467 u32 reg, val, reclaim;
468 u32 tom, gfxstolen, gttsize;
469 size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase,
470 tsegbase, mestolenbase;
471 size_t tsegbasedelta, remapbase, remaplimit;
472 uint16_t ggc;
473
474 mmiosize = get_mmio_size();
475
476 ggc = pci_read_config16(NORTHBRIDGE, GGC);
477 if (!(ggc & 2)) {
478 gfxstolen = ((ggc >> 3) & 0x1f) * 32;
479 gttsize = ((ggc >> 8) & 0x3);
480 } else {
481 gfxstolen = 0;
482 gttsize = 0;
483 }
484
485 tsegsize = CONFIG_SMM_TSEG_SIZE >> 20;
486
487 tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1];
488
489 mestolenbase = tom - me_uma_size;
490
491 toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize,
492 tom - me_uma_size);
493 gfxstolenbase = toludbase - gfxstolen;
494 gttbase = gfxstolenbase - gttsize;
495
496 tsegbase = gttbase - tsegsize;
497
498 // Round tsegbase down to nearest address aligned to tsegsize
499 tsegbasedelta = tsegbase & (tsegsize - 1);
500 tsegbase &= ~(tsegsize - 1);
501
502 gttbase -= tsegbasedelta;
503 gfxstolenbase -= tsegbasedelta;
504 toludbase -= tsegbasedelta;
505
506 // Test if it is possible to reclaim a hole in the RAM addressing
507 if (tom - me_uma_size > toludbase) {
508 // Reclaim is possible
509 reclaim = 1;
510 remapbase = MAX(4096, tom - me_uma_size);
511 remaplimit =
512 remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1;
513 touudbase = remaplimit + 1;
514 } else {
515 // Reclaim not possible
516 reclaim = 0;
517 touudbase = tom - me_uma_size;
518 }
519
520 // Update memory map in pci-e configuration space
521 printk(BIOS_DEBUG, "Update PCI-E configuration space:\n");
522
523 // TOM (top of memory)
Felix Held4902fee2019-12-28 18:09:47 +0100524 reg = pci_read_config32(PCI_DEV(0, 0, 0), TOM);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100525 val = tom & 0xfff;
526 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100527 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TOM, reg);
528 pci_write_config32(PCI_DEV(0, 0, 0), TOM, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100529
Felix Held4902fee2019-12-28 18:09:47 +0100530 reg = pci_read_config32(PCI_DEV(0, 0, 0), TOM + 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100531 val = tom & 0xfffff000;
532 reg = (reg & ~0x000fffff) | (val >> 12);
Felix Held4902fee2019-12-28 18:09:47 +0100533 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TOM + 4, reg);
534 pci_write_config32(PCI_DEV(0, 0, 0), TOM + 4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100535
536 // TOLUD (top of low used dram)
Felix Held4902fee2019-12-28 18:09:47 +0100537 reg = pci_read_config32(PCI_DEV(0, 0, 0), TOLUD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100538 val = toludbase & 0xfff;
539 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100540 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TOLUD, reg);
541 pci_write_config32(PCI_DEV(0, 0, 0), TOLUD, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100542
543 // TOUUD LSB (top of upper usable dram)
Felix Held4902fee2019-12-28 18:09:47 +0100544 reg = pci_read_config32(PCI_DEV(0, 0, 0), TOUUD);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100545 val = touudbase & 0xfff;
546 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100547 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TOUUD, reg);
548 pci_write_config32(PCI_DEV(0, 0, 0), TOUUD, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100549
550 // TOUUD MSB
Felix Held4902fee2019-12-28 18:09:47 +0100551 reg = pci_read_config32(PCI_DEV(0, 0, 0), TOUUD + 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100552 val = touudbase & 0xfffff000;
553 reg = (reg & ~0x000fffff) | (val >> 12);
Felix Held4902fee2019-12-28 18:09:47 +0100554 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TOUUD + 4, reg);
555 pci_write_config32(PCI_DEV(0, 0, 0), TOUUD + 4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100556
557 if (reclaim) {
558 // REMAP BASE
Felix Held4902fee2019-12-28 18:09:47 +0100559 pci_write_config32(PCI_DEV(0, 0, 0), REMAPBASE, remapbase << 20);
560 pci_write_config32(PCI_DEV(0, 0, 0), REMAPBASE + 4, remapbase >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100561
562 // REMAP LIMIT
Felix Held4902fee2019-12-28 18:09:47 +0100563 pci_write_config32(PCI_DEV(0, 0, 0), REMAPLIMIT, remaplimit << 20);
564 pci_write_config32(PCI_DEV(0, 0, 0), REMAPLIMIT + 4, remaplimit >> 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100565 }
566 // TSEG
Felix Held4902fee2019-12-28 18:09:47 +0100567 reg = pci_read_config32(PCI_DEV(0, 0, 0), TSEGMB);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100568 val = tsegbase & 0xfff;
569 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100570 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", TSEGMB, reg);
571 pci_write_config32(PCI_DEV(0, 0, 0), TSEGMB, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100572
573 // GFX stolen memory
Felix Held4902fee2019-12-28 18:09:47 +0100574 reg = pci_read_config32(PCI_DEV(0, 0, 0), BDSM);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100575 val = gfxstolenbase & 0xfff;
576 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100577 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", BDSM, reg);
578 pci_write_config32(PCI_DEV(0, 0, 0), BDSM, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100579
580 // GTT stolen memory
Felix Held4902fee2019-12-28 18:09:47 +0100581 reg = pci_read_config32(PCI_DEV(0, 0, 0), BGSM);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100582 val = gttbase & 0xfff;
583 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held4902fee2019-12-28 18:09:47 +0100584 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", BGSM, reg);
585 pci_write_config32(PCI_DEV(0, 0, 0), BGSM, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100586
587 if (me_uma_size) {
Felix Held651f99f2019-12-30 16:28:48 +0100588 reg = pci_read_config32(PCI_DEV(0, 0, 0), MESEG_MASK + 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100589 val = (0x80000 - me_uma_size) & 0xfffff000;
590 reg = (reg & ~0x000fffff) | (val >> 12);
Felix Held651f99f2019-12-30 16:28:48 +0100591 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", MESEG_MASK + 4, reg);
592 pci_write_config32(PCI_DEV(0, 0, 0), MESEG_MASK + 4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100593
594 // ME base
Felix Held651f99f2019-12-30 16:28:48 +0100595 reg = pci_read_config32(PCI_DEV(0, 0, 0), MESEG_BASE);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100596 val = mestolenbase & 0xfff;
597 reg = (reg & ~0xfff00000) | (val << 20);
Felix Held651f99f2019-12-30 16:28:48 +0100598 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", MESEG_BASE, reg);
599 pci_write_config32(PCI_DEV(0, 0, 0), MESEG_BASE, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100600
Felix Held651f99f2019-12-30 16:28:48 +0100601 reg = pci_read_config32(PCI_DEV(0, 0, 0), MESEG_BASE + 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100602 val = mestolenbase & 0xfffff000;
603 reg = (reg & ~0x000fffff) | (val >> 12);
Felix Held651f99f2019-12-30 16:28:48 +0100604 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", MESEG_BASE + 4, reg);
605 pci_write_config32(PCI_DEV(0, 0, 0), MESEG_BASE + 4, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100606
607 // ME mask
Felix Held651f99f2019-12-30 16:28:48 +0100608 reg = pci_read_config32(PCI_DEV(0, 0, 0), MESEG_MASK);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100609 val = (0x80000 - me_uma_size) & 0xfff;
610 reg = (reg & ~0xfff00000) | (val << 20);
Felix Heldf54ae382019-12-30 18:18:02 +0100611 reg = reg | ME_STLEN_EN; // set ME memory enable
612 reg = reg | MELCK; // set lockbit on ME mem
Felix Held651f99f2019-12-30 16:28:48 +0100613 printk(BIOS_DEBUG, "PCI(0, 0, 0)[%x] = %x\n", MESEG_MASK, reg);
614 pci_write_config32(PCI_DEV(0, 0, 0), MESEG_MASK, reg);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100615 }
616}
617
618static void wait_428c(int channel)
619{
620 while (1) {
Felix Held2bb3cdf2018-07-28 00:23:59 +0200621 if (MCHBAR32(0x428c + (channel << 10)) & 0x50)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100622 return;
623 }
624}
625
626static void write_reset(ramctr_timing * ctrl)
627{
628 int channel, slotrank;
629
630 /* choose a populated channel. */
631 channel = (ctrl->rankmap[0]) ? 0 : 1;
632
633 wait_428c(channel);
634
635 /* choose a populated rank. */
636 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
637
638 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200639 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
640 MCHBAR32(0x4230 + 0x400 * channel) = 0x80c01;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200641 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +0200642 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100643
Felix Held9cf1dd22018-07-31 14:52:40 +0200644 // execute command queue - why is bit 22 set here?!
645 MCHBAR32(0x4284 + 0x400 * channel) = (1 << 22) | RUN_QUEUE_4284(1);
646
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100647 wait_428c(channel);
648}
649
650void dram_jedecreset(ramctr_timing * ctrl)
651{
Felix Held9fe248f2018-07-31 20:59:45 +0200652 u32 reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100653 int channel;
654
655 while (!(MCHBAR32(0x5084) & 0x10000));
656 do {
657 reg = MCHBAR32(0x428c);
658 } while ((reg & 0x14) == 0);
659
660 // Set state of memory controller
661 reg = 0x112;
662 MCHBAR32(0x5030) = reg;
663 MCHBAR32(0x4ea0) = 0;
664 reg |= 2; //ddr reset
665 MCHBAR32(0x5030) = reg;
666
667 // Assert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200668 MCHBAR32_AND(0x5030, ~0x2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100669
670 // Wait 200us
671 udelay(200);
672
673 // Deassert dimm reset signal
Felix Held9fe248f2018-07-31 20:59:45 +0200674 MCHBAR32_OR(0x5030, 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100675
676 // Wait 500us
677 udelay(500);
678
679 // Enable DCLK
Felix Held9fe248f2018-07-31 20:59:45 +0200680 MCHBAR32_OR(0x5030, 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100681
682 // XXX Wait 20ns
683 udelay(1);
684
685 FOR_ALL_CHANNELS {
686 // Set valid rank CKE
Felix Held9fe248f2018-07-31 20:59:45 +0200687 reg = ctrl->rankmap[channel];
688 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100689
690 // Wait 10ns for ranks to settle
691 //udelay(0.01);
692
693 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
Felix Held9fe248f2018-07-31 20:59:45 +0200694 MCHBAR32(0x42a0 + 0x400 * channel) = reg;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100695
696 // Write reset using a NOP
697 write_reset(ctrl);
698 }
699}
700
701static odtmap get_ODT(ramctr_timing *ctrl, u8 rank, int channel)
702{
703 /* Get ODT based on rankmap: */
704 int dimms_per_ch = (ctrl->rankmap[channel] & 1)
705 + ((ctrl->rankmap[channel] >> 2) & 1);
706
707 if (dimms_per_ch == 1) {
708 return (const odtmap){60, 60};
709 } else {
710 return (const odtmap){120, 30};
711 }
712}
713
714static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank,
715 int reg, u32 val)
716{
717 wait_428c(channel);
718
719 if (ctrl->rank_mirror[channel][slotrank]) {
720 /* DDR3 Rank1 Address mirror
721 * swap the following pins:
722 * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
723 reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
724 val = (val & ~0x1f8) | ((val >> 1) & 0xa8)
725 | ((val & 0xa8) << 1);
726 }
727
728 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200729 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f000;
730 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
731 MCHBAR32(0x4200 + 0x400 * channel) =
732 (slotrank << 24) | (reg << 20) | val | 0x60000;
733 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100734
735 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200736 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f000;
737 MCHBAR32(0x4234 + 0x400 * channel) = 0x41001;
738 MCHBAR32(0x4204 + 0x400 * channel) =
739 (slotrank << 24) | (reg << 20) | val | 0x60000;
740 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100741
742 /* DRAM command MRS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200743 MCHBAR32(0x4228 + 0x400 * channel) = 0x0f000;
744 MCHBAR32(0x4238 + 0x400 * channel) = 0x1001 | (ctrl->tMOD << 16);
745 MCHBAR32(0x4208 + 0x400 * channel) =
746 (slotrank << 24) | (reg << 20) | val | 0x60000;
747 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200748
749 // execute command queue
750 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100751}
752
753static u32 make_mr0(ramctr_timing * ctrl, u8 rank)
754{
755 u16 mr0reg, mch_cas, mch_wr;
756 static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 };
Patrick Rudolph74203de2017-11-20 11:57:01 +0100757 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100758
759 /* DLL Reset - self clearing - set after CLK frequency has been changed */
760 mr0reg = 0x100;
761
762 // Convert CAS to MCH register friendly
763 if (ctrl->CAS < 12) {
764 mch_cas = (u16) ((ctrl->CAS - 4) << 1);
765 } else {
766 mch_cas = (u16) (ctrl->CAS - 12);
767 mch_cas = ((mch_cas << 1) | 0x1);
768 }
769
770 // Convert tWR to MCH register friendly
771 mch_wr = mch_wr_t[ctrl->tWR - 5];
772
773 mr0reg = (mr0reg & ~0x4) | ((mch_cas & 0x1) << 2);
774 mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3);
775 mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9);
776
777 // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature
Patrick Rudolph74203de2017-11-20 11:57:01 +0100778 mr0reg = (mr0reg & ~0x1000) | (!is_mobile << 12);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100779 return mr0reg;
780}
781
782static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel)
783{
Felix Held2bb3cdf2018-07-28 00:23:59 +0200784 write_mrreg(ctrl, channel, rank, 0, make_mr0(ctrl, rank));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100785}
786
787static u32 encode_odt(u32 odt)
788{
789 switch (odt) {
790 case 30:
791 return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4
792 case 60:
793 return (1 << 2); // RZQ/4
794 case 120:
795 return (1 << 6); // RZQ/2
796 default:
797 case 0:
798 return 0;
799 }
800}
801
802static u32 make_mr1(ramctr_timing *ctrl, u8 rank, int channel)
803{
804 odtmap odt;
805 u32 mr1reg;
806
807 odt = get_ODT(ctrl, rank, channel);
808 mr1reg = 0x2;
809
810 mr1reg |= encode_odt(odt.rttnom);
811
812 return mr1reg;
813}
814
815static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel)
816{
817 u16 mr1reg;
818
819 mr1reg = make_mr1(ctrl, rank, channel);
820
821 write_mrreg(ctrl, channel, rank, 1, mr1reg);
822}
823
824static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel)
825{
826 u16 pasr, cwl, mr2reg;
827 odtmap odt;
828 int srt;
829
830 pasr = 0;
831 cwl = ctrl->CWL - 5;
832 odt = get_ODT(ctrl, rank, channel);
833
834 srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh;
835
836 mr2reg = 0;
837 mr2reg = (mr2reg & ~0x7) | pasr;
838 mr2reg = (mr2reg & ~0x38) | (cwl << 3);
839 mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6);
840 mr2reg = (mr2reg & ~0x80) | (srt << 7);
841 mr2reg |= (odt.rttwr / 60) << 9;
842
843 write_mrreg(ctrl, channel, rank, 2, mr2reg);
844}
845
846static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel)
847{
848 write_mrreg(ctrl, channel, rank, 3, 0);
849}
850
851void dram_mrscommands(ramctr_timing * ctrl)
852{
853 u8 slotrank;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100854 int channel;
855
856 FOR_ALL_POPULATED_CHANNELS {
857 FOR_ALL_POPULATED_RANKS {
858 // MR2
859 dram_mr2(ctrl, slotrank, channel);
860
861 // MR3
862 dram_mr3(ctrl, slotrank, channel);
863
864 // MR1
865 dram_mr1(ctrl, slotrank, channel);
866
867 // MR0
868 dram_mr0(ctrl, slotrank, channel);
869 }
870 }
871
872 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200873 MCHBAR32(0x4e20) = 0x7;
874 MCHBAR32(0x4e30) = 0xf1001;
875 MCHBAR32(0x4e00) = 0x60002;
876 MCHBAR32(0x4e10) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100877
878 /* DRAM command ZQCL */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200879 MCHBAR32(0x4e24) = 0x1f003;
880 MCHBAR32(0x4e34) = 0x1901001;
881 MCHBAR32(0x4e04) = 0x60400;
882 MCHBAR32(0x4e14) = 0x288;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100883
Felix Held9cf1dd22018-07-31 14:52:40 +0200884 // execute command queue on all channels? Why isn't bit 0 set here?
Felix Held2bb3cdf2018-07-28 00:23:59 +0200885 MCHBAR32(0x4e84) = 0x40004;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100886
887 // Drain
888 FOR_ALL_CHANNELS {
889 // Wait for ref drained
890 wait_428c(channel);
891 }
892
893 // Refresh enable
Felix Held9fe248f2018-07-31 20:59:45 +0200894 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100895
896 FOR_ALL_POPULATED_CHANNELS {
Felix Held9fe248f2018-07-31 20:59:45 +0200897 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100898
899 wait_428c(channel);
900
901 slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
902
903 // Drain
904 wait_428c(channel);
905
906 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +0200907 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
908 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
909 MCHBAR32(0x4200 + 0x400 * channel) =
910 (slotrank << 24) | 0x60000;
911 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Felix Held9cf1dd22018-07-31 14:52:40 +0200912
913 // execute command queue
914 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100915
916 // Drain
917 wait_428c(channel);
918 }
919}
920
921static const u32 lane_registers[] = {
922 0x0000, 0x0200, 0x0400, 0x0600,
923 0x1000, 0x1200, 0x1400, 0x1600,
924 0x0800
925};
926
927void program_timings(ramctr_timing * ctrl, int channel)
928{
Felix Helddee167e2019-12-30 17:30:16 +0100929 u32 reg32, reg_4024, reg_c14, reg_c18, reg_io_latency;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100930 int lane;
931 int slotrank, slot;
932 int full_shift = 0;
933 u16 slot320c[NUM_SLOTS];
934
935 FOR_ALL_POPULATED_RANKS {
936 if (full_shift < -ctrl->timings[channel][slotrank].val_320c)
937 full_shift = -ctrl->timings[channel][slotrank].val_320c;
938 }
939
940 for (slot = 0; slot < NUM_SLOTS; slot++)
941 switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) {
942 case 0:
943 default:
944 slot320c[slot] = 0x7f;
945 break;
946 case 1:
947 slot320c[slot] =
948 ctrl->timings[channel][2 * slot + 0].val_320c +
949 full_shift;
950 break;
951 case 2:
952 slot320c[slot] =
953 ctrl->timings[channel][2 * slot + 1].val_320c +
954 full_shift;
955 break;
956 case 3:
957 slot320c[slot] =
958 (ctrl->timings[channel][2 * slot].val_320c +
Felix Held2bb3cdf2018-07-28 00:23:59 +0200959 ctrl->timings[channel][2 * slot + 1].val_320c) / 2 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100960 full_shift;
961 break;
962 }
963
964 /* enable CMD XOVER */
965 reg32 = get_XOVER_CMD(ctrl->rankmap[channel]);
966 reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9);
967 reg32 |= (slot320c[1] & 0x7f) << 18;
968 reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6);
969
970 MCHBAR32(0x320c + 0x100 * channel) = reg32;
971
972 /* enable CLK XOVER */
973 reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]);
974 reg_c18 = 0;
975
976 FOR_ALL_POPULATED_RANKS {
977 int shift =
978 ctrl->timings[channel][slotrank].val_320c + full_shift;
979 int offset_val_c14;
980 if (shift < 0)
981 shift = 0;
982 offset_val_c14 = ctrl->reg_c14_offset + shift;
983 /* set CLK phase shift */
984 reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank);
985 reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank;
986 }
987
988 MCHBAR32(0xc14 + channel * 0x100) = reg_c14;
989 MCHBAR32(0xc18 + channel * 0x100) = reg_c18;
990
Felix Helddee167e2019-12-30 17:30:16 +0100991 reg_io_latency = MCHBAR32(SC_IO_LATENCY_C0 + 0x400 * channel);
992 reg_io_latency &= 0xffff0000;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100993
994 reg_4024 = 0;
995
996 FOR_ALL_POPULATED_RANKS {
997 int post_timA_min_high = 7, post_timA_max_high = 0;
998 int pre_timA_min_high = 7, pre_timA_max_high = 0;
999 int shift_402x = 0;
1000 int shift =
1001 ctrl->timings[channel][slotrank].val_320c + full_shift;
1002
1003 if (shift < 0)
1004 shift = 0;
1005
1006 FOR_ALL_LANES {
Arthur Heymansabc504f2017-05-15 09:36:44 +02001007 post_timA_min_high = MIN(post_timA_min_high,
1008 (ctrl->timings[channel][slotrank].lanes[lane].
1009 timA + shift) >> 6);
1010 pre_timA_min_high = MIN(pre_timA_min_high,
1011 ctrl->timings[channel][slotrank].lanes[lane].
1012 timA >> 6);
1013 post_timA_max_high = MAX(post_timA_max_high,
1014 (ctrl->timings[channel][slotrank].lanes[lane].
1015 timA + shift) >> 6);
1016 pre_timA_max_high = MAX(pre_timA_max_high,
1017 ctrl->timings[channel][slotrank].lanes[lane].
1018 timA >> 6);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001019 }
1020
1021 if (pre_timA_max_high - pre_timA_min_high <
1022 post_timA_max_high - post_timA_min_high)
1023 shift_402x = +1;
1024 else if (pre_timA_max_high - pre_timA_min_high >
1025 post_timA_max_high - post_timA_min_high)
1026 shift_402x = -1;
1027
Felix Helddee167e2019-12-30 17:30:16 +01001028 reg_io_latency |=
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001029 (ctrl->timings[channel][slotrank].val_4028 + shift_402x -
1030 post_timA_min_high) << (4 * slotrank);
1031 reg_4024 |=
1032 (ctrl->timings[channel][slotrank].val_4024 +
1033 shift_402x) << (8 * slotrank);
1034
1035 FOR_ALL_LANES {
1036 MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel +
1037 4 * slotrank)
1038 =
1039 (((ctrl->timings[channel][slotrank].lanes[lane].
1040 timA + shift) & 0x3f)
1041 |
1042 ((ctrl->timings[channel][slotrank].lanes[lane].
1043 rising + shift) << 8)
1044 |
1045 (((ctrl->timings[channel][slotrank].lanes[lane].
1046 timA + shift -
1047 (post_timA_min_high << 6)) & 0x1c0) << 10)
1048 | ((ctrl->timings[channel][slotrank].lanes[lane].
1049 falling + shift) << 20));
1050
1051 MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel +
1052 4 * slotrank)
1053 =
1054 (((ctrl->timings[channel][slotrank].lanes[lane].
1055 timC + shift) & 0x3f)
1056 |
1057 (((ctrl->timings[channel][slotrank].lanes[lane].
1058 timB + shift) & 0x3f) << 8)
1059 |
1060 (((ctrl->timings[channel][slotrank].lanes[lane].
1061 timB + shift) & 0x1c0) << 9)
1062 |
1063 (((ctrl->timings[channel][slotrank].lanes[lane].
1064 timC + shift) & 0x40) << 13));
1065 }
1066 }
1067 MCHBAR32(0x4024 + 0x400 * channel) = reg_4024;
Felix Helddee167e2019-12-30 17:30:16 +01001068 MCHBAR32(SC_IO_LATENCY_C0 + 0x400 * channel) = reg_io_latency;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001069}
1070
1071static void test_timA(ramctr_timing * ctrl, int channel, int slotrank)
1072{
1073 wait_428c(channel);
1074
1075 /* DRAM command MRS
1076 * write MR3 MPR enable
1077 * in this mode only RD and RDA are allowed
1078 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001079 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1080 MCHBAR32(0x4230 + 0x400 * channel) = (0xc01 | (ctrl->tMOD << 16));
1081 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x360004;
1082 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001083
1084 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001085 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1086 MCHBAR32(0x4234 + 0x400 * channel) = 0x4040c01;
1087 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
1088 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001089
1090 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001091 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1092 MCHBAR32(0x4238 + 0x400 * channel) = 0x100f | ((ctrl->CAS + 36) << 16);
1093 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1094 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001095
1096 /* DRAM command MRS
1097 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001098 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1099 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
1100 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x360000;
1101 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001102
Felix Held9cf1dd22018-07-31 14:52:40 +02001103 // execute command queue
1104 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001105
1106 wait_428c(channel);
1107}
1108
1109static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank,
1110 int lane)
1111{
1112 u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001113 return ((MCHBAR32(lane_registers[lane] + channel * 0x100 + 4 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001114 ((timA / 32) & 1) * 4)
1115 >> (timA % 32)) & 1);
1116}
1117
1118struct run {
1119 int middle;
1120 int end;
1121 int start;
1122 int all;
1123 int length;
1124};
1125
1126static struct run get_longest_zero_run(int *seq, int sz)
1127{
1128 int i, ls;
1129 int bl = 0, bs = 0;
1130 struct run ret;
1131
1132 ls = 0;
1133 for (i = 0; i < 2 * sz; i++)
1134 if (seq[i % sz]) {
1135 if (i - ls > bl) {
1136 bl = i - ls;
1137 bs = ls;
1138 }
1139 ls = i + 1;
1140 }
1141 if (bl == 0) {
1142 ret.middle = sz / 2;
1143 ret.start = 0;
1144 ret.end = sz;
Jacob Garbere0c181d2019-04-08 22:21:43 -06001145 ret.length = sz;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001146 ret.all = 1;
1147 return ret;
1148 }
1149
1150 ret.start = bs % sz;
1151 ret.end = (bs + bl - 1) % sz;
1152 ret.middle = (bs + (bl - 1) / 2) % sz;
1153 ret.length = bl;
1154 ret.all = 0;
1155
1156 return ret;
1157}
1158
1159static void discover_timA_coarse(ramctr_timing * ctrl, int channel,
1160 int slotrank, int *upperA)
1161{
1162 int timA;
1163 int statistics[NUM_LANES][128];
1164 int lane;
1165
1166 for (timA = 0; timA < 128; timA++) {
1167 FOR_ALL_LANES {
1168 ctrl->timings[channel][slotrank].lanes[lane].timA = timA;
1169 }
1170 program_timings(ctrl, channel);
1171
1172 test_timA(ctrl, channel, slotrank);
1173
1174 FOR_ALL_LANES {
1175 statistics[lane][timA] =
1176 !does_lane_work(ctrl, channel, slotrank, lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001177 }
1178 }
1179 FOR_ALL_LANES {
1180 struct run rn = get_longest_zero_run(statistics[lane], 128);
1181 ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle;
1182 upperA[lane] = rn.end;
1183 if (upperA[lane] < rn.middle)
1184 upperA[lane] += 128;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001185 printram("timA: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001186 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001187 }
1188}
1189
1190static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank,
1191 int *upperA)
1192{
1193 int timA_delta;
1194 int statistics[NUM_LANES][51];
1195 int lane, i;
1196
1197 memset(statistics, 0, sizeof(statistics));
1198
1199 for (timA_delta = -25; timA_delta <= 25; timA_delta++) {
1200 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1201 timA = upperA[lane] + timA_delta + 0x40;
1202 program_timings(ctrl, channel);
1203
1204 for (i = 0; i < 100; i++) {
1205 test_timA(ctrl, channel, slotrank);
1206 FOR_ALL_LANES {
1207 statistics[lane][timA_delta + 25] +=
Felix Held2bb3cdf2018-07-28 00:23:59 +02001208 does_lane_work(ctrl, channel, slotrank,
1209 lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001210 }
1211 }
1212 }
1213 FOR_ALL_LANES {
1214 int last_zero, first_all;
1215
1216 for (last_zero = -25; last_zero <= 25; last_zero++)
1217 if (statistics[lane][last_zero + 25])
1218 break;
1219 last_zero--;
1220 for (first_all = -25; first_all <= 25; first_all++)
1221 if (statistics[lane][first_all + 25] == 100)
1222 break;
1223
1224 printram("lane %d: %d, %d\n", lane, last_zero,
1225 first_all);
1226
1227 ctrl->timings[channel][slotrank].lanes[lane].timA =
1228 (last_zero + first_all) / 2 + upperA[lane];
1229 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1230 lane, ctrl->timings[channel][slotrank].lanes[lane].timA);
1231 }
1232}
1233
1234static int discover_402x(ramctr_timing *ctrl, int channel, int slotrank,
1235 int *upperA)
1236{
1237 int works[NUM_LANES];
1238 int lane;
1239 while (1) {
1240 int all_works = 1, some_works = 0;
1241 program_timings(ctrl, channel);
1242 test_timA(ctrl, channel, slotrank);
1243 FOR_ALL_LANES {
1244 works[lane] =
1245 !does_lane_work(ctrl, channel, slotrank, lane);
1246 if (works[lane])
1247 some_works = 1;
1248 else
1249 all_works = 0;
1250 }
1251 if (all_works)
1252 return 0;
1253 if (!some_works) {
1254 if (ctrl->timings[channel][slotrank].val_4024 < 2) {
1255 printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n",
1256 channel, slotrank);
1257 return MAKE_ERR;
1258 }
1259 ctrl->timings[channel][slotrank].val_4024 -= 2;
1260 printram("4024 -= 2;\n");
1261 continue;
1262 }
1263 ctrl->timings[channel][slotrank].val_4028 += 2;
1264 printram("4028 += 2;\n");
1265 if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) {
1266 printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n",
1267 channel, slotrank);
1268 return MAKE_ERR;
1269 }
1270 FOR_ALL_LANES if (works[lane]) {
1271 ctrl->timings[channel][slotrank].lanes[lane].timA +=
1272 128;
1273 upperA[lane] += 128;
1274 printram("increment %d, %d, %d\n", channel,
1275 slotrank, lane);
1276 }
1277 }
1278 return 0;
1279}
1280
1281struct timA_minmax {
1282 int timA_min_high, timA_max_high;
1283};
1284
1285static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1286 struct timA_minmax *mnmx)
1287{
1288 int lane;
1289 mnmx->timA_min_high = 7;
1290 mnmx->timA_max_high = 0;
1291
1292 FOR_ALL_LANES {
1293 if (mnmx->timA_min_high >
1294 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1295 mnmx->timA_min_high =
1296 (ctrl->timings[channel][slotrank].lanes[lane].
1297 timA >> 6);
1298 if (mnmx->timA_max_high <
1299 (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6))
1300 mnmx->timA_max_high =
1301 (ctrl->timings[channel][slotrank].lanes[lane].
1302 timA >> 6);
1303 }
1304}
1305
1306static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank,
1307 struct timA_minmax *mnmx)
1308{
1309 struct timA_minmax post;
1310 int shift_402x = 0;
1311
1312 /* Get changed maxima. */
1313 pre_timA_change(ctrl, channel, slotrank, &post);
1314
1315 if (mnmx->timA_max_high - mnmx->timA_min_high <
1316 post.timA_max_high - post.timA_min_high)
1317 shift_402x = +1;
1318 else if (mnmx->timA_max_high - mnmx->timA_min_high >
1319 post.timA_max_high - post.timA_min_high)
1320 shift_402x = -1;
1321 else
1322 shift_402x = 0;
1323
1324 ctrl->timings[channel][slotrank].val_4028 += shift_402x;
1325 ctrl->timings[channel][slotrank].val_4024 += shift_402x;
1326 printram("4024 += %d;\n", shift_402x);
1327 printram("4028 += %d;\n", shift_402x);
1328}
1329
1330/* Compensate the skew between DQS and DQs.
1331 * To ease PCB design a small skew between Data Strobe signals and
1332 * Data Signals is allowed.
1333 * The controller has to measure and compensate this skew for every byte-lane.
1334 * By delaying either all DQs signals or DQS signal, a full phase
1335 * shift can be introduced.
1336 * It is assumed that one byte-lane's DQs signals have the same routing delay.
1337 *
1338 * To measure the actual skew, the DRAM is placed in "read leveling" mode.
1339 * In read leveling mode the DRAM-chip outputs an alternating periodic pattern.
1340 * The memory controller iterates over all possible values to do a full phase shift
1341 * and issues read commands.
1342 * With DQS and DQs in phase the data read is expected to alternate on every byte:
1343 * 0xFF 0x00 0xFF ...
1344 * Once the controller has detected this pattern a bit in the result register is
1345 * set for the current phase shift.
1346 */
1347int read_training(ramctr_timing * ctrl)
1348{
1349 int channel, slotrank, lane;
1350 int err;
1351
1352 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
1353 int all_high, some_high;
1354 int upperA[NUM_LANES];
1355 struct timA_minmax mnmx;
1356
Felix Held2bb3cdf2018-07-28 00:23:59 +02001357 wait_428c(channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001358
Felix Held2bb3cdf2018-07-28 00:23:59 +02001359 /* DRAM command PREA */
1360 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1361 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1362 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1363 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001364
1365 // execute command queue
1366 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001367
Felix Held2bb3cdf2018-07-28 00:23:59 +02001368 MCHBAR32(0x3400) = (slotrank << 2) | 0x8001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001369
Felix Held2bb3cdf2018-07-28 00:23:59 +02001370 ctrl->timings[channel][slotrank].val_4028 = 4;
1371 ctrl->timings[channel][slotrank].val_4024 = 55;
1372 program_timings(ctrl, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001373
Felix Held2bb3cdf2018-07-28 00:23:59 +02001374 discover_timA_coarse(ctrl, channel, slotrank, upperA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001375
Felix Held2bb3cdf2018-07-28 00:23:59 +02001376 all_high = 1;
1377 some_high = 0;
1378 FOR_ALL_LANES {
1379 if (ctrl->timings[channel][slotrank].lanes[lane].timA >=
1380 0x40)
1381 some_high = 1;
1382 else
1383 all_high = 0;
1384 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001385
1386 if (all_high) {
1387 ctrl->timings[channel][slotrank].val_4028--;
1388 printram("4028--;\n");
1389 FOR_ALL_LANES {
1390 ctrl->timings[channel][slotrank].lanes[lane].
1391 timA -= 0x40;
1392 upperA[lane] -= 0x40;
1393
1394 }
1395 } else if (some_high) {
1396 ctrl->timings[channel][slotrank].val_4024++;
1397 ctrl->timings[channel][slotrank].val_4028++;
1398 printram("4024++;\n");
1399 printram("4028++;\n");
1400 }
1401
1402 program_timings(ctrl, channel);
1403
1404 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1405
1406 err = discover_402x(ctrl, channel, slotrank, upperA);
1407 if (err)
1408 return err;
1409
1410 post_timA_change(ctrl, channel, slotrank, &mnmx);
1411 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1412
1413 discover_timA_fine(ctrl, channel, slotrank, upperA);
1414
1415 post_timA_change(ctrl, channel, slotrank, &mnmx);
1416 pre_timA_change(ctrl, channel, slotrank, &mnmx);
1417
1418 FOR_ALL_LANES {
1419 ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40;
1420 }
1421 ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high;
1422 printram("4028 -= %d;\n", mnmx.timA_min_high);
1423
1424 post_timA_change(ctrl, channel, slotrank, &mnmx);
1425
1426 printram("4/8: %d, %d, %x, %x\n", channel, slotrank,
1427 ctrl->timings[channel][slotrank].val_4024,
1428 ctrl->timings[channel][slotrank].val_4028);
1429
1430 printram("final results:\n");
1431 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02001432 printram("Aval: %d, %d, %d: %x\n", channel, slotrank,
1433 lane,
1434 ctrl->timings[channel][slotrank].lanes[lane].timA);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001435
Felix Held2bb3cdf2018-07-28 00:23:59 +02001436 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001437
1438 toggle_io_reset();
1439 }
1440
1441 FOR_ALL_POPULATED_CHANNELS {
1442 program_timings(ctrl, channel);
1443 }
1444 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001445 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001446 }
1447 return 0;
1448}
1449
1450static void test_timC(ramctr_timing * ctrl, int channel, int slotrank)
1451{
1452 int lane;
1453
1454 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001455 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02001456 MCHBAR32(0x4140 + 0x400 * channel + 4 * lane);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001457 }
1458
1459 wait_428c(channel);
1460
1461 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001462 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1463 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001464 (MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001465 | 4 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001466 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | (6 << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001467 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001468
1469 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001470 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1471 MCHBAR32(0x4234 + 0x400 * channel) = 0x8041001;
1472 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 8;
1473 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001474
1475 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001476 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1477 MCHBAR32(0x4238 + 0x400 * channel) = 0x80411f4;
1478 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
1479 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001480
1481 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001482 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1483 MCHBAR32(0x423c + 0x400 * channel) =
1484 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1485 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 8;
1486 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001487
Felix Held9cf1dd22018-07-31 14:52:40 +02001488 // execute command queue
1489 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001490
1491 wait_428c(channel);
1492
1493 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001494 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1495 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1496 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
1497 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001498
1499 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001500 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1501 MCHBAR32(0x4234 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001502 (MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02001503 | 8 | (ctrl->CAS << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001504 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001505 MCHBAR32(0x4214 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001506
1507 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001508 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1509 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01001510 0x40011f4 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001511 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1512 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001513
1514 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001515 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
1516 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
1517 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
1518 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001519
1520 // execute command queue
1521 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1522
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001523 wait_428c(channel);
1524}
1525
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001526static void timC_threshold_process(int *data, const int count)
1527{
1528 int min = data[0];
1529 int max = min;
1530 int i;
1531 for (i = 1; i < count; i++) {
1532 if (min > data[i])
1533 min = data[i];
1534 if (max < data[i])
1535 max = data[i];
1536 }
1537 int threshold = min/2 + max/2;
1538 for (i = 0; i < count; i++)
1539 data[i] = data[i] > threshold;
1540 printram("threshold=%d min=%d max=%d\n",
1541 threshold, min, max);
1542}
1543
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001544static int discover_timC(ramctr_timing *ctrl, int channel, int slotrank)
1545{
1546 int timC;
1547 int statistics[NUM_LANES][MAX_TIMC + 1];
1548 int lane;
1549
1550 wait_428c(channel);
1551
1552 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001553 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1554 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRP << 16);
Felix Held9fe248f2018-07-31 20:59:45 +02001555 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60400;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001556 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Felix Held9cf1dd22018-07-31 14:52:40 +02001557
1558 // execute command queue
1559 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001560
1561 for (timC = 0; timC <= MAX_TIMC; timC++) {
1562 FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane].
1563 timC = timC;
1564 program_timings(ctrl, channel);
1565
1566 test_timC(ctrl, channel, slotrank);
1567
1568 FOR_ALL_LANES {
1569 statistics[lane][timC] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001570 MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001571 }
1572 }
1573 FOR_ALL_LANES {
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001574 struct run rn = get_longest_zero_run(
1575 statistics[lane], ARRAY_SIZE(statistics[lane]));
1576 if (rn.all || rn.length < 8) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001577 printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n",
1578 channel, slotrank, lane);
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001579 /* With command training not happend yet, the lane can
1580 * be erroneous. Take the avarage as reference and try
1581 * again to find a run.
1582 */
1583 timC_threshold_process(statistics[lane],
1584 ARRAY_SIZE(statistics[lane]));
1585 rn = get_longest_zero_run(statistics[lane],
1586 ARRAY_SIZE(statistics[lane]));
1587 if (rn.all || rn.length < 8) {
1588 printk(BIOS_EMERG, "timC recovery failed\n");
1589 return MAKE_ERR;
1590 }
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001591 }
Tobias Diedrich87c4f112017-12-07 22:40:20 +01001592 ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle;
Patrick Rudolph368b6152016-11-25 16:36:52 +01001593 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
Felix Held2bb3cdf2018-07-28 00:23:59 +02001594 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001595 }
1596 return 0;
1597}
1598
1599static int get_precedening_channels(ramctr_timing * ctrl, int target_channel)
1600{
1601 int channel, ret = 0;
1602 FOR_ALL_POPULATED_CHANNELS if (channel < target_channel)
1603 ret++;
1604 return ret;
1605}
1606
1607static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b)
1608{
Subrata Banikb1434fc2019-03-15 22:20:41 +05301609 unsigned int j;
1610 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001611 get_precedening_channels(ctrl, channel) * 0x40;
1612 for (j = 0; j < 16; j++)
1613 write32((void *)(0x04000000 + channel_offset + 4 * j), j & 2 ? b : a);
1614 sfence();
1615}
1616
1617static int num_of_channels(const ramctr_timing * ctrl)
1618{
1619 int ret = 0;
1620 int channel;
1621 FOR_ALL_POPULATED_CHANNELS ret++;
1622 return ret;
1623}
1624
1625static void fill_pattern1(ramctr_timing * ctrl, int channel)
1626{
Subrata Banikb1434fc2019-03-15 22:20:41 +05301627 unsigned int j;
1628 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001629 get_precedening_channels(ctrl, channel) * 0x40;
Subrata Banikb1434fc2019-03-15 22:20:41 +05301630 unsigned int channel_step = 0x40 * num_of_channels(ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001631 for (j = 0; j < 16; j++)
1632 write32((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff);
1633 for (j = 0; j < 16; j++)
1634 write32((void *)(0x04000000 + channel_offset + channel_step + j * 4), 0);
1635 sfence();
1636}
1637
1638static void precharge(ramctr_timing * ctrl)
1639{
1640 int channel, slotrank, lane;
1641
1642 FOR_ALL_POPULATED_CHANNELS {
1643 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1644 ctrl->timings[channel][slotrank].lanes[lane].falling =
1645 16;
1646 ctrl->timings[channel][slotrank].lanes[lane].rising =
1647 16;
1648 }
1649
1650 program_timings(ctrl, channel);
1651
1652 FOR_ALL_POPULATED_RANKS {
1653 wait_428c(channel);
1654
1655 /* DRAM command MRS
1656 * write MR3 MPR enable
1657 * in this mode only RD and RDA are allowed
1658 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001659 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1660 MCHBAR32(0x4230 + 0x400 * channel) =
1661 0xc01 | (ctrl->tMOD << 16);
1662 MCHBAR32(0x4200 + 0x400 * channel) =
1663 (slotrank << 24) | 0x360004;
1664 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001665
1666 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001667 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1668 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1669 MCHBAR32(0x4204 + 0x400 * channel) =
1670 (slotrank << 24) | 0;
1671 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001672
1673 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001674 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1675 MCHBAR32(0x4238 + 0x400 * channel) =
1676 0x1001 | ((ctrl->CAS + 8) << 16);
1677 MCHBAR32(0x4208 + 0x400 * channel) =
1678 (slotrank << 24) | 0x60000;
1679 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001680
1681 /* DRAM command MRS
1682 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001683 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1684 MCHBAR32(0x423c + 0x400 * channel) =
1685 0xc01 | (ctrl->tMOD << 16);
1686 MCHBAR32(0x420c + 0x400 * channel) =
1687 (slotrank << 24) | 0x360000;
1688 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02001689
1690 // execute command queue
1691 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001692
1693 wait_428c(channel);
1694 }
1695
1696 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
1697 ctrl->timings[channel][slotrank].lanes[lane].falling =
1698 48;
1699 ctrl->timings[channel][slotrank].lanes[lane].rising =
1700 48;
1701 }
1702
1703 program_timings(ctrl, channel);
1704
1705 FOR_ALL_POPULATED_RANKS {
1706 wait_428c(channel);
1707 /* DRAM command MRS
1708 * write MR3 MPR enable
1709 * in this mode only RD and RDA are allowed
1710 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001711 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
1712 MCHBAR32(0x4230 + 0x400 * channel) =
1713 0xc01 | (ctrl->tMOD << 16);
1714 MCHBAR32(0x4200 + 0x400 * channel) =
1715 (slotrank << 24) | 0x360004;
1716 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001717
1718 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001719 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
1720 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
1721 MCHBAR32(0x4204 + 0x400 * channel) =
1722 (slotrank << 24) | 0;
1723 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001724
1725 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001726 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
1727 MCHBAR32(0x4238 + 0x400 * channel) =
1728 0x1001 | ((ctrl->CAS + 8) << 16);
1729 MCHBAR32(0x4208 + 0x400 * channel) =
1730 (slotrank << 24) | 0x60000;
1731 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001732
1733 /* DRAM command MRS
1734 * write MR3 MPR disable */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001735 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
1736 MCHBAR32(0x423c + 0x400 * channel) =
1737 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001738 MCHBAR32(0x420c + 0x400 * channel) =
1739 (slotrank << 24) | 0x360000;
1740 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001741
Felix Held9cf1dd22018-07-31 14:52:40 +02001742 // execute command queue
1743 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
1744
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001745 wait_428c(channel);
1746 }
1747 }
1748}
1749
1750static void test_timB(ramctr_timing * ctrl, int channel, int slotrank)
1751{
1752 /* enable DQs on this slotrank */
1753 write_mrreg(ctrl, channel, slotrank, 1,
1754 0x80 | make_mr1(ctrl, slotrank, channel));
1755
1756 wait_428c(channel);
1757 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001758 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f207;
1759 MCHBAR32(0x4230 + 0x400 * channel) =
1760 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16);
1761 MCHBAR32(0x4200 + 0x400 * channel) = 8 | (slotrank << 24);
1762 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001763
1764 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001765 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f107;
1766 MCHBAR32(0x4234 + 0x400 * channel) =
1767 0x4000c01 | ((ctrl->CAS + 38) << 16);
1768 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 4;
1769 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001770
Felix Held9cf1dd22018-07-31 14:52:40 +02001771 // execute command queue
1772 MCHBAR32(0x400 * channel + 0x4284) = RUN_QUEUE_4284(2);
1773
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001774 wait_428c(channel);
1775
1776 /* disable DQs on this slotrank */
1777 write_mrreg(ctrl, channel, slotrank, 1,
1778 0x1080 | make_mr1(ctrl, slotrank, channel));
1779}
1780
1781static int discover_timB(ramctr_timing *ctrl, int channel, int slotrank)
1782{
1783 int timB;
1784 int statistics[NUM_LANES][128];
1785 int lane;
1786
Felix Held2bb3cdf2018-07-28 00:23:59 +02001787 MCHBAR32(0x3400) = 0x108052 | (slotrank << 2);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001788
1789 for (timB = 0; timB < 128; timB++) {
1790 FOR_ALL_LANES {
1791 ctrl->timings[channel][slotrank].lanes[lane].timB = timB;
1792 }
1793 program_timings(ctrl, channel);
1794
1795 test_timB(ctrl, channel, slotrank);
1796
1797 FOR_ALL_LANES {
1798 statistics[lane][timB] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02001799 !((MCHBAR32(lane_registers[lane] +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001800 channel * 0x100 + 4 + ((timB / 32) & 1) * 4)
1801 >> (timB % 32)) & 1);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001802 }
1803 }
1804 FOR_ALL_LANES {
1805 struct run rn = get_longest_zero_run(statistics[lane], 128);
1806 /* timC is a direct function of timB's 6 LSBs.
1807 * Some tests increments the value of timB by a small value,
1808 * which might cause the 6bit value to overflow, if it's close
1809 * to 0x3F. Increment the value by a small offset if it's likely
1810 * to overflow, to make sure it won't overflow while running
1811 * tests and bricks the system due to a non matching timC.
1812 *
1813 * TODO: find out why some tests (edge write discovery)
1814 * increment timB. */
1815 if ((rn.start & 0x3F) == 0x3E)
1816 rn.start += 2;
1817 else if ((rn.start & 0x3F) == 0x3F)
1818 rn.start += 1;
1819 ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start;
1820 if (rn.all) {
1821 printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n",
1822 channel, slotrank, lane);
1823 return MAKE_ERR;
1824 }
Patrick Rudolph368b6152016-11-25 16:36:52 +01001825 printram("timB: %d, %d, %d: 0x%02x-0x%02x-0x%02x\n",
1826 channel, slotrank, lane, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001827 }
1828 return 0;
1829}
1830
1831static int get_timB_high_adjust(u64 val)
1832{
1833 int i;
1834
1835 /* good */
1836 if (val == 0xffffffffffffffffLL)
1837 return 0;
1838
1839 if (val >= 0xf000000000000000LL) {
1840 /* needs negative adjustment */
1841 for (i = 0; i < 8; i++)
1842 if (val << (8 * (7 - i) + 4))
1843 return -i;
1844 } else {
1845 /* needs positive adjustment */
1846 for (i = 0; i < 8; i++)
1847 if (val >> (8 * (7 - i) + 4))
1848 return i;
1849 }
1850 return 8;
1851}
1852
1853static void adjust_high_timB(ramctr_timing * ctrl)
1854{
1855 int channel, slotrank, lane, old;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001856 MCHBAR32(0x3400) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001857 FOR_ALL_POPULATED_CHANNELS {
1858 fill_pattern1(ctrl, channel);
Felix Held2bb3cdf2018-07-28 00:23:59 +02001859 MCHBAR32(0x4288 + (channel << 10)) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001860 }
1861 FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS {
1862
Felix Held2bb3cdf2018-07-28 00:23:59 +02001863 MCHBAR32(0x4288 + 0x400 * channel) = 0x10001;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001864
1865 wait_428c(channel);
1866
1867 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001868 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
1869 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tRCD << 16);
1870 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1871 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001872
1873 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001874 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f207;
1875 MCHBAR32(0x4234 + 0x400 * channel) = 0x8040c01;
1876 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x8;
1877 MCHBAR32(0x4214 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001878
1879 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001880 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f201;
1881 MCHBAR32(0x4238 + 0x400 * channel) = 0x8041003;
1882 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
1883 MCHBAR32(0x4218 + 0x400 * channel) = 0x3e2;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001884
1885 /* DRAM command NOP */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001886 MCHBAR32(0x422c + 0x400 * channel) = 0x1f207;
1887 MCHBAR32(0x423c + 0x400 * channel) =
1888 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16);
1889 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x8;
1890 MCHBAR32(0x421c + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001891
Felix Held9cf1dd22018-07-31 14:52:40 +02001892 // execute command queue
1893 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001894
1895 wait_428c(channel);
1896
1897 /* DRAM command PREA */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001898 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f002;
1899 MCHBAR32(0x4230 + 0x400 * channel) =
1900 0xc01 | ((ctrl->tRP) << 16);
1901 MCHBAR32(0x4200 + 0x400 * channel) =
1902 (slotrank << 24) | 0x60400;
1903 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001904
1905 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001906 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f006;
1907 MCHBAR32(0x4234 + 0x400 * channel) =
1908 0xc01 | ((ctrl->tRCD) << 16);
1909 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24) | 0x60000;
1910 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001911
1912 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001913 MCHBAR32(0x4228 + 0x400 * channel) = 0x3f105;
1914 MCHBAR32(0x4238 + 0x400 * channel) = 0x4000c01 | ((ctrl->tRP +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001915 ctrl->timings[channel][slotrank].val_4024 +
Felix Held2bb3cdf2018-07-28 00:23:59 +02001916 ctrl->timings[channel][slotrank].val_4028) << 16);
1917 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60008;
1918 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001919
Felix Held9cf1dd22018-07-31 14:52:40 +02001920 // execute command queue
1921 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(3);
1922
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001923 wait_428c(channel);
1924 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02001925 u64 res = MCHBAR32(lane_registers[lane] +
1926 0x100 * channel + 4);
1927 res |= ((u64) MCHBAR32(lane_registers[lane] +
1928 0x100 * channel + 8)) << 32;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001929 old = ctrl->timings[channel][slotrank].lanes[lane].timB;
1930 ctrl->timings[channel][slotrank].lanes[lane].timB +=
1931 get_timB_high_adjust(res) * 64;
1932
1933 printram("High adjust %d:%016llx\n", lane, res);
1934 printram("Bval+: %d, %d, %d, %x -> %x\n", channel,
1935 slotrank, lane, old,
1936 ctrl->timings[channel][slotrank].lanes[lane].
1937 timB);
1938 }
1939 }
Felix Held2bb3cdf2018-07-28 00:23:59 +02001940 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001941}
1942
1943static void write_op(ramctr_timing * ctrl, int channel)
1944{
1945 int slotrank;
1946
1947 wait_428c(channel);
1948
1949 /* choose an existing rank. */
1950 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
1951
1952 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02001953 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
1954 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001955 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02001956 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001957
Felix Held9cf1dd22018-07-31 14:52:40 +02001958 // execute command queue
1959 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
1960
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001961 wait_428c(channel);
1962}
1963
1964/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes.
1965 * DDR3 adopted the fly-by topology. The data and strobes signals reach
1966 * the chips at different times with respect to command, address and
1967 * clock signals.
1968 * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase
1969 * shift can be introduced.
1970 * It is assumed that the CLK/ADDR/CMD signals have the same routing delay.
1971 *
1972 * To find the required phase shift the DRAM is placed in "write leveling" mode.
1973 * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the
1974 * sampled value on the data lanes (DQs).
1975 */
1976int write_training(ramctr_timing * ctrl)
1977{
1978 int channel, slotrank, lane;
1979 int err;
1980
1981 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02001982 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001983
1984 FOR_ALL_POPULATED_CHANNELS {
1985 write_op(ctrl, channel);
Felix Held2463aa92018-07-29 21:37:55 +02001986 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001987 }
1988
1989 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02001990 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01001991 FOR_ALL_POPULATED_CHANNELS {
1992 write_op(ctrl, channel);
1993 }
1994
1995 /* enable write leveling on all ranks
1996 * disable all DQ outputs
1997 * only NOP is allowed in this mode */
1998 FOR_ALL_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02001999 FOR_ALL_POPULATED_RANKS
2000 write_mrreg(ctrl, channel, slotrank, 1,
2001 make_mr1(ctrl, slotrank, channel) | 0x1080);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002002
Felix Held2bb3cdf2018-07-28 00:23:59 +02002003 MCHBAR32(0x3400) = 0x108052;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002004
2005 toggle_io_reset();
2006
2007 /* set any valid value for timB, it gets corrected later */
2008 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2009 err = discover_timB(ctrl, channel, slotrank);
2010 if (err)
2011 return err;
2012 }
2013
2014 /* disable write leveling on all ranks */
2015 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS
2016 write_mrreg(ctrl, channel,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002017 slotrank, 1, make_mr1(ctrl, slotrank, channel));
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002018
Felix Held2bb3cdf2018-07-28 00:23:59 +02002019 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002020
2021 FOR_ALL_POPULATED_CHANNELS
2022 wait_428c(channel);
2023
2024 /* refresh enable */
Felix Held2463aa92018-07-29 21:37:55 +02002025 MCHBAR32_OR(0x5030, 8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002026
2027 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002028 MCHBAR32_AND(0x4020 + 0x400 * channel, ~0x00200000);
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002029 MCHBAR32(0x428c + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002030 wait_428c(channel);
2031
2032 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002033 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2034 MCHBAR32(0x4230 + 0x400 * channel) = 0x659001;
2035 MCHBAR32(0x4200 + 0x400 * channel) = 0x60000;
2036 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002037
Felix Held9cf1dd22018-07-31 14:52:40 +02002038 // execute command queue
2039 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2040
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002041 wait_428c(channel);
2042 }
2043
2044 toggle_io_reset();
2045
2046 printram("CPE\n");
2047 precharge(ctrl);
2048 printram("CPF\n");
2049
2050 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002051 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002052 }
2053
2054 FOR_ALL_POPULATED_CHANNELS {
2055 fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002056 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002057 }
2058
2059 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2060 err = discover_timC(ctrl, channel, slotrank);
2061 if (err)
2062 return err;
2063 }
2064
2065 FOR_ALL_POPULATED_CHANNELS
2066 program_timings(ctrl, channel);
2067
2068 /* measure and adjust timB timings */
2069 adjust_high_timB(ctrl);
2070
2071 FOR_ALL_POPULATED_CHANNELS
2072 program_timings(ctrl, channel);
2073
2074 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Heldb802c072018-07-29 21:46:19 +02002075 MCHBAR32_AND(0x4080 + 0x400 * channel + 4 * lane, 0);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002076 }
2077 return 0;
2078}
2079
2080static int test_320c(ramctr_timing * ctrl, int channel, int slotrank)
2081{
2082 struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank];
2083 int timC_delta;
2084 int lanes_ok = 0;
2085 int ctr = 0;
2086 int lane;
2087
2088 for (timC_delta = -5; timC_delta <= 5; timC_delta++) {
2089 FOR_ALL_LANES {
2090 ctrl->timings[channel][slotrank].lanes[lane].timC =
2091 saved_rt.lanes[lane].timC + timC_delta;
2092 }
2093 program_timings(ctrl, channel);
2094 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002095 MCHBAR32(4 * lane + 0x4f40) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002096 }
2097
Felix Held2bb3cdf2018-07-28 00:23:59 +02002098 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002099
2100 wait_428c(channel);
2101 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002102 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2103 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002104 ((MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002105 | 8 | (ctrl->tRCD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002106 MCHBAR32(0x4200 + 0x400 * channel) =
2107 (slotrank << 24) | ctr | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002108 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Felix Held9fe248f2018-07-31 20:59:45 +02002109
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002110 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002111 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2112 MCHBAR32(0x4234 + 0x400 * channel) =
2113 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16);
2114 MCHBAR32(0x4204 + 0x400 * channel) = (slotrank << 24);
2115 MCHBAR32(0x4244 + 0x400 * channel) = 0x389abcd;
2116 MCHBAR32(0x4214 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002117
2118 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002119 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2120 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002121 0x4001020 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002122 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24);
2123 MCHBAR32(0x4248 + 0x400 * channel) = 0x389abcd;
2124 MCHBAR32(0x4218 + 0x400 * channel) = 0x20e42;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002125
2126 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002127 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2128 MCHBAR32(0x423c + 0x400 * channel) = 0xf1001;
2129 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2130 MCHBAR32(0x421c + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002131
Felix Held9cf1dd22018-07-31 14:52:40 +02002132 // execute command queue
2133 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2134
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002135 wait_428c(channel);
2136 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002137 u32 r32 = MCHBAR32(0x4340 + 4 * lane + 0x400 * channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002138
2139 if (r32 == 0)
2140 lanes_ok |= 1 << lane;
2141 }
2142 ctr++;
2143 if (lanes_ok == ((1 << NUM_LANES) - 1))
2144 break;
2145 }
2146
2147 ctrl->timings[channel][slotrank] = saved_rt;
2148
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002149 return lanes_ok != ((1 << NUM_LANES) - 1);
2150}
2151
2152#include "raminit_patterns.h"
2153
2154static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno)
2155{
Subrata Banikb1434fc2019-03-15 22:20:41 +05302156 unsigned int i, j;
2157 unsigned int channel_offset =
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002158 get_precedening_channels(ctrl, channel) * 0x40;
Subrata Banikb1434fc2019-03-15 22:20:41 +05302159 unsigned int channel_step = 0x40 * num_of_channels(ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002160
2161 if (patno) {
2162 u8 base8 = 0x80 >> ((patno - 1) % 8);
2163 u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24);
2164 for (i = 0; i < 32; i++) {
2165 for (j = 0; j < 16; j++) {
2166 u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0;
2167 if (invert[patno - 1][i] & (1 << (j / 2)))
2168 val = ~val;
2169 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2170 j * 4), val);
2171 }
2172 }
2173
2174 } else {
2175 for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
2176 for (j = 0; j < 16; j++)
2177 write32((void *)(0x04000000 + channel_offset + i * channel_step +
2178 j * 4), pattern[i][j]);
2179 }
2180 sfence();
2181 }
2182}
2183
2184static void reprogram_320c(ramctr_timing * ctrl)
2185{
2186 int channel, slotrank;
2187
2188 FOR_ALL_POPULATED_CHANNELS {
2189 wait_428c(channel);
2190
2191 /* choose an existing rank. */
2192 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2193
2194 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002195 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2196 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002197 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002198 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002199
Felix Held9cf1dd22018-07-31 14:52:40 +02002200 // execute command queue
2201 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2202
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002203 wait_428c(channel);
Felix Held2463aa92018-07-29 21:37:55 +02002204 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002205 }
2206
2207 /* refresh disable */
Felix Held2463aa92018-07-29 21:37:55 +02002208 MCHBAR32_AND(0x5030, ~8);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002209 FOR_ALL_POPULATED_CHANNELS {
2210 wait_428c(channel);
2211
2212 /* choose an existing rank. */
2213 slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
2214
2215 /* DRAM command ZQCS */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002216 MCHBAR32(0x4220 + 0x400 * channel) = 0x0f003;
2217 MCHBAR32(0x4230 + 0x400 * channel) = 0x41001;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002218 MCHBAR32(0x4200 + 0x400 * channel) = (slotrank << 24) | 0x60000;
Felix Held2bb3cdf2018-07-28 00:23:59 +02002219 MCHBAR32(0x4210 + 0x400 * channel) = 0x3e0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002220
Felix Held9cf1dd22018-07-31 14:52:40 +02002221 // execute command queue
2222 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(1);
2223
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002224 wait_428c(channel);
2225 }
2226
2227 /* jedec reset */
2228 dram_jedecreset(ctrl);
2229 /* mrs commands. */
2230 dram_mrscommands(ctrl);
2231
2232 toggle_io_reset();
2233}
2234
2235#define MIN_C320C_LEN 13
2236
2237static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch)
2238{
2239 struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS];
2240 int slotrank;
2241 int c320c;
2242 int stat[NUM_SLOTRANKS][256];
2243 int delta = 0;
2244
2245 printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel);
2246
2247 FOR_ALL_POPULATED_RANKS {
2248 saved_timings[channel][slotrank] =
2249 ctrl->timings[channel][slotrank];
2250 }
2251
2252 ctrl->cmd_stretch[channel] = cmd_stretch;
2253
2254 MCHBAR32(0x4004 + 0x400 * channel) =
2255 ctrl->tRRD
2256 | (ctrl->tRTP << 4)
2257 | (ctrl->tCKE << 8)
2258 | (ctrl->tWTR << 12)
2259 | (ctrl->tFAW << 16)
2260 | (ctrl->tWR << 24)
2261 | (ctrl->cmd_stretch[channel] << 30);
2262
2263 if (ctrl->cmd_stretch[channel] == 2)
2264 delta = 2;
2265 else if (ctrl->cmd_stretch[channel] == 0)
2266 delta = 4;
2267
2268 FOR_ALL_POPULATED_RANKS {
2269 ctrl->timings[channel][slotrank].val_4024 -= delta;
2270 }
2271
2272 for (c320c = -127; c320c <= 127; c320c++) {
2273 FOR_ALL_POPULATED_RANKS {
2274 ctrl->timings[channel][slotrank].val_320c = c320c;
2275 }
2276 program_timings(ctrl, channel);
2277 reprogram_320c(ctrl);
2278 FOR_ALL_POPULATED_RANKS {
2279 stat[slotrank][c320c + 127] =
2280 test_320c(ctrl, channel, slotrank);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002281 }
2282 }
2283 FOR_ALL_POPULATED_RANKS {
2284 struct run rn =
2285 get_longest_zero_run(stat[slotrank], 255);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002286 ctrl->timings[channel][slotrank].val_320c = rn.middle - 127;
Patrick Rudolph368b6152016-11-25 16:36:52 +01002287 printram("cmd_stretch: %d, %d: 0x%02x-0x%02x-0x%02x\n",
2288 channel, slotrank, rn.start, rn.middle, rn.end);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002289 if (rn.all || rn.length < MIN_C320C_LEN) {
2290 FOR_ALL_POPULATED_RANKS {
2291 ctrl->timings[channel][slotrank] =
2292 saved_timings[channel][slotrank];
2293 }
2294 return MAKE_ERR;
2295 }
2296 }
2297
2298 return 0;
2299}
2300
2301/* Adjust CMD phase shift and try multiple command rates.
2302 * A command rate of 2T doubles the time needed for address and
2303 * command decode. */
2304int command_training(ramctr_timing *ctrl)
2305{
2306 int channel;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002307
2308 FOR_ALL_POPULATED_CHANNELS {
2309 fill_pattern5(ctrl, channel, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002310 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002311 }
2312
2313 FOR_ALL_POPULATED_CHANNELS {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002314 int cmdrate, err;
2315
2316 /*
2317 * Dual DIMM per channel:
2318 * Issue: While c320c discovery seems to succeed raminit
2319 * will fail in write training.
2320 * Workaround: Skip 1T in dual DIMM mode, that's only
2321 * supported by a few DIMMs.
Dan Elkoubydabebc32018-04-13 18:47:10 +03002322 * Only try 1T mode for XMP DIMMs that request it in dual DIMM
2323 * mode.
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002324 *
2325 * Single DIMM per channel:
2326 * Try command rate 1T and 2T
2327 */
2328 cmdrate = ((ctrl->rankmap[channel] & 0x5) == 0x5);
Dan Elkoubydabebc32018-04-13 18:47:10 +03002329 if (ctrl->tCMD)
2330 /* XMP gives the CMD rate in clock ticks, not ns */
2331 cmdrate = MIN(DIV_ROUND_UP(ctrl->tCMD, 256) - 1, 1);
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002332
Elyes HAOUASadda3f812018-01-31 23:02:35 +01002333 for (; cmdrate < 2; cmdrate++) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002334 err = try_cmd_stretch(ctrl, channel, cmdrate << 1);
2335
2336 if (!err)
2337 break;
2338 }
2339
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002340 if (err) {
Patrick Rudolph58d16af2017-06-19 19:33:12 +02002341 printk(BIOS_EMERG, "c320c discovery failed\n");
2342 return err;
2343 }
2344
2345 printram("Using CMD rate %uT on channel %u\n",
2346 cmdrate + 1, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002347 }
2348
2349 FOR_ALL_POPULATED_CHANNELS
2350 program_timings(ctrl, channel);
2351
2352 reprogram_320c(ctrl);
2353 return 0;
2354}
2355
2356
2357static int discover_edges_real(ramctr_timing *ctrl, int channel, int slotrank,
2358 int *edges)
2359{
2360 int edge;
2361 int statistics[NUM_LANES][MAX_EDGE_TIMING + 1];
2362 int lane;
2363
2364 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2365 FOR_ALL_LANES {
2366 ctrl->timings[channel][slotrank].lanes[lane].rising =
2367 edge;
2368 ctrl->timings[channel][slotrank].lanes[lane].falling =
2369 edge;
2370 }
2371 program_timings(ctrl, channel);
2372
2373 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002374 MCHBAR32(0x4340 + 0x400 * channel + 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002375 MCHBAR32(0x400 * channel + 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002376 }
2377
2378 wait_428c(channel);
2379 /* DRAM command MRS
2380 * write MR3 MPR enable
2381 * in this mode only RD and RDA are allowed
2382 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002383 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
Felix Held2463aa92018-07-29 21:37:55 +02002384 MCHBAR32(0x4230 + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002385 MCHBAR32(0x4200 + 0x400 * channel) =
2386 (slotrank << 24) | 0x360004;
2387 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002388
2389 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002390 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2391 MCHBAR32(0x4234 + 0x400 * channel) = 0x40411f4;
2392 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2393 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002394
2395 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002396 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2397 MCHBAR32(0x4238 + 0x400 * channel) =
2398 0x1001 | ((ctrl->CAS + 8) << 16);
2399 MCHBAR32(0x4208 + 0x400 * channel) = (slotrank << 24) | 0x60000;
2400 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002401
2402 /* DRAM command MRS
2403 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002404 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2405 MCHBAR32(0x423c + 0x400 * channel) = 0xc01 | (ctrl->tMOD << 16);
2406 MCHBAR32(0x420c + 0x400 * channel) =
2407 (slotrank << 24) | 0x360000;
2408 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002409
Felix Held9cf1dd22018-07-31 14:52:40 +02002410 // execute command queue
2411 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002412
2413 wait_428c(channel);
2414
2415 FOR_ALL_LANES {
2416 statistics[lane][edge] =
Felix Held2bb3cdf2018-07-28 00:23:59 +02002417 MCHBAR32(0x4340 + 0x400 * channel + lane * 4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002418 }
2419 }
2420 FOR_ALL_LANES {
2421 struct run rn =
2422 get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1);
2423 edges[lane] = rn.middle;
2424 if (rn.all) {
2425 printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n",
2426 channel, slotrank, lane);
2427 return MAKE_ERR;
2428 }
2429 printram("eval %d, %d, %d: %02x\n", channel, slotrank,
2430 lane, edges[lane]);
2431 }
2432 return 0;
2433}
2434
2435int discover_edges(ramctr_timing *ctrl)
2436{
2437 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2438 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2439 int channel, slotrank, lane;
2440 int err;
2441
Felix Held2bb3cdf2018-07-28 00:23:59 +02002442 MCHBAR32(0x3400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002443
2444 toggle_io_reset();
2445
2446 FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002447 MCHBAR32(4 * lane + 0x400 * channel + 0x4080) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002448 }
2449
2450 FOR_ALL_POPULATED_CHANNELS {
2451 fill_pattern0(ctrl, channel, 0, 0);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002452 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002453 FOR_ALL_LANES {
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002454 MCHBAR32(0x400 * channel + lane * 4 + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002455 }
2456
2457 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2458 ctrl->timings[channel][slotrank].lanes[lane].falling =
2459 16;
2460 ctrl->timings[channel][slotrank].lanes[lane].rising =
2461 16;
2462 }
2463
2464 program_timings(ctrl, channel);
2465
2466 FOR_ALL_POPULATED_RANKS {
2467 wait_428c(channel);
2468
2469 /* DRAM command MRS
2470 * MR3 enable MPR
2471 * write MR3 MPR enable
2472 * in this mode only RD and RDA are allowed
2473 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002474 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2475 MCHBAR32(0x4230 + 0x400 * channel) =
2476 0xc01 | (ctrl->tMOD << 16);
2477 MCHBAR32(0x4200 + 0x400 * channel) =
2478 (slotrank << 24) | 0x360004;
2479 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002480
2481 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002482 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2483 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2484 MCHBAR32(0x4204 + 0x400 * channel) =
2485 (slotrank << 24) | 0;
2486 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002487
2488 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002489 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2490 MCHBAR32(0x4238 + 0x400 * channel) =
2491 0x1001 | ((ctrl->CAS + 8) << 16);
2492 MCHBAR32(0x4208 + 0x400 * channel) =
2493 (slotrank << 24) | 0x60000;
2494 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002495
2496 /* DRAM command MRS
2497 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002498 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2499 MCHBAR32(0x423c + 0x400 * channel) =
2500 0xc01 | (ctrl->tMOD << 16);
2501 MCHBAR32(0x420c + 0x400 * channel) =
2502 (slotrank << 24) | 0x360000;
2503 MCHBAR32(0x421c + 0x400 * channel) = 0;
Felix Held9cf1dd22018-07-31 14:52:40 +02002504
2505 // execute command queue
2506 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002507
2508 wait_428c(channel);
2509 }
2510
2511 /* XXX: check any measured value ? */
2512
2513 FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2514 ctrl->timings[channel][slotrank].lanes[lane].falling =
2515 48;
2516 ctrl->timings[channel][slotrank].lanes[lane].rising =
2517 48;
2518 }
2519
2520 program_timings(ctrl, channel);
2521
2522 FOR_ALL_POPULATED_RANKS {
2523 wait_428c(channel);
2524
2525 /* DRAM command MRS
2526 * MR3 enable MPR
2527 * write MR3 MPR enable
2528 * in this mode only RD and RDA are allowed
2529 * all reads return a predefined pattern */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002530 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f000;
2531 MCHBAR32(0x4230 + 0x400 * channel) =
2532 0xc01 | (ctrl->tMOD << 16);
2533 MCHBAR32(0x4200 + 0x400 * channel) =
2534 (slotrank << 24) | 0x360004;
2535 MCHBAR32(0x4210 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002536
2537 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002538 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f105;
2539 MCHBAR32(0x4234 + 0x400 * channel) = 0x4041003;
2540 MCHBAR32(0x4204 + 0x400 * channel) =
2541 (slotrank << 24) | 0;
2542 MCHBAR32(0x4214 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002543
2544 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002545 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2546 MCHBAR32(0x4238 + 0x400 * channel) =
2547 0x1001 | ((ctrl->CAS + 8) << 16);
2548 MCHBAR32(0x4208 + 0x400 * channel) =
2549 (slotrank << 24) | 0x60000;
2550 MCHBAR32(0x4218 + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002551
2552 /* DRAM command MRS
2553 * MR3 disable MPR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002554 MCHBAR32(0x422c + 0x400 * channel) = 0x1f000;
2555 MCHBAR32(0x423c + 0x400 * channel) =
2556 0xc01 | (ctrl->tMOD << 16);
2557 MCHBAR32(0x420c + 0x400 * channel) =
2558 (slotrank << 24) | 0x360000;
2559 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002560
Felix Held9cf1dd22018-07-31 14:52:40 +02002561 // execute command queue
2562 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2563
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002564 wait_428c(channel);
2565 }
2566
2567 /* XXX: check any measured value ? */
2568
2569 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002570 MCHBAR32(0x4080 + 0x400 * channel + lane * 4) =
2571 ~MCHBAR32(0x4040 + 0x400 * channel + lane * 4)
2572 & 0xff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002573 }
2574
2575 fill_pattern0(ctrl, channel, 0, 0xffffffff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002576 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002577 }
2578
2579 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002580 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002581 printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300);
2582
2583 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2584 err = discover_edges_real(ctrl, channel, slotrank,
Felix Held2bb3cdf2018-07-28 00:23:59 +02002585 falling_edges[channel][slotrank]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002586 if (err)
2587 return err;
2588 }
2589
Felix Held2bb3cdf2018-07-28 00:23:59 +02002590 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002591 printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200);
2592
2593 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2594 err = discover_edges_real(ctrl, channel, slotrank,
2595 rising_edges[channel][slotrank]);
2596 if (err)
2597 return err;
2598 }
2599
Felix Held2bb3cdf2018-07-28 00:23:59 +02002600 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002601
2602 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2603 ctrl->timings[channel][slotrank].lanes[lane].falling =
2604 falling_edges[channel][slotrank][lane];
2605 ctrl->timings[channel][slotrank].lanes[lane].rising =
2606 rising_edges[channel][slotrank][lane];
2607 }
2608
2609 FOR_ALL_POPULATED_CHANNELS {
2610 program_timings(ctrl, channel);
2611 }
2612
2613 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002614 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002615 }
2616 return 0;
2617}
2618
2619static int discover_edges_write_real(ramctr_timing *ctrl, int channel,
2620 int slotrank, int *edges)
2621{
2622 int edge;
2623 u32 raw_statistics[MAX_EDGE_TIMING + 1];
2624 int statistics[MAX_EDGE_TIMING + 1];
2625 const int reg3000b24[] = { 0, 0xc, 0x2c };
2626 int lane, i;
2627 int lower[NUM_LANES];
2628 int upper[NUM_LANES];
2629 int pat;
2630
2631 FOR_ALL_LANES {
2632 lower[lane] = 0;
2633 upper[lane] = MAX_EDGE_TIMING;
2634 }
2635
2636 for (i = 0; i < 3; i++) {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002637 MCHBAR32(0x3000 + 0x100 * channel) = reg3000b24[i] << 24;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002638 printram("[%x] = 0x%08x\n",
2639 0x3000 + 0x100 * channel, reg3000b24[i] << 24);
2640 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2641 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002642 MCHBAR32(0x4288 + 0x400 * channel) = 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002643 printram("using pattern %d\n", pat);
2644 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) {
2645 FOR_ALL_LANES {
2646 ctrl->timings[channel][slotrank].lanes[lane].
2647 rising = edge;
2648 ctrl->timings[channel][slotrank].lanes[lane].
2649 falling = edge;
2650 }
2651 program_timings(ctrl, channel);
2652
2653 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002654 MCHBAR32(0x4340 + 0x400 * channel +
2655 4 * lane) = 0;
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002656 MCHBAR32(0x400 * channel +
Felix Held2bb3cdf2018-07-28 00:23:59 +02002657 4 * lane + 0x4140);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002658 }
2659 wait_428c(channel);
2660
2661 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002662 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2663 MCHBAR32(0x4230 + 0x400 * channel) =
2664 0x4 | (ctrl->tRCD << 16) |
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002665 (MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002666 << 10);
2667 MCHBAR32(0x4200 + 0x400 * channel) =
2668 (slotrank << 24) | 0x60000;
2669 MCHBAR32(0x4210 + 0x400 * channel) = 0x240;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002670
2671 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002672 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2673 MCHBAR32(0x4234 + 0x400 * channel) = 0x8005020 |
2674 ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2675 MCHBAR32(0x4204 + 0x400 * channel) =
2676 slotrank << 24;
2677 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002678
2679 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002680 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2681 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002682 0x4005020 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002683 MCHBAR32(0x4208 + 0x400 * channel) =
2684 slotrank << 24;
2685 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002686
2687 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002688 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2689 MCHBAR32(0x423c + 0x400 * channel) =
2690 0xc01 | (ctrl->tRP << 16);
2691 MCHBAR32(0x420c + 0x400 * channel) =
2692 (slotrank << 24) | 0x60400;
2693 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002694
Felix Held9cf1dd22018-07-31 14:52:40 +02002695 // execute command queue
2696 MCHBAR32(0x4284 + 0x400 * channel) =
2697 RUN_QUEUE_4284(4);
2698
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002699 wait_428c(channel);
2700 FOR_ALL_LANES {
Elyes HAOUAS9c8895f2019-05-22 19:57:43 +02002701 MCHBAR32(0x4340 +
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002702 0x400 * channel + lane * 4);
2703 }
2704
2705 raw_statistics[edge] =
2706 MCHBAR32(0x436c + 0x400 * channel);
2707 }
2708 FOR_ALL_LANES {
2709 struct run rn;
2710 for (edge = 0; edge <= MAX_EDGE_TIMING; edge++)
2711 statistics[edge] =
2712 ! !(raw_statistics[edge] & (1 << lane));
2713 rn = get_longest_zero_run(statistics,
2714 MAX_EDGE_TIMING + 1);
2715 printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2716 channel, slotrank, i, rn.start, rn.middle,
2717 rn.end, rn.start + ctrl->edge_offset[i],
2718 rn.end - ctrl->edge_offset[i]);
2719 lower[lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002720 MAX(rn.start + ctrl->edge_offset[i], lower[lane]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002721 upper[lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002722 MIN(rn.end - ctrl->edge_offset[i], upper[lane]);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002723 edges[lane] = (lower[lane] + upper[lane]) / 2;
2724 if (rn.all || (lower[lane] > upper[lane])) {
2725 printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n",
2726 channel, slotrank, lane);
2727 return MAKE_ERR;
2728 }
2729 }
2730 }
2731 }
2732
Felix Held2bb3cdf2018-07-28 00:23:59 +02002733 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002734 printram("CPA\n");
2735 return 0;
2736}
2737
2738int discover_edges_write(ramctr_timing *ctrl)
2739{
2740 int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2741 int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2742 int channel, slotrank, lane;
2743 int err;
2744
2745 /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002746 MCHBAR32(0x4eb0) = 0x300;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002747 printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300);
2748
2749 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2750 err = discover_edges_write_real(ctrl, channel, slotrank,
2751 falling_edges[channel][slotrank]);
2752 if (err)
2753 return err;
2754 }
2755
Felix Held2bb3cdf2018-07-28 00:23:59 +02002756 MCHBAR32(0x4eb0) = 0x200;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002757 printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200);
2758
2759 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2760 err = discover_edges_write_real(ctrl, channel, slotrank,
2761 rising_edges[channel][slotrank]);
2762 if (err)
2763 return err;
2764 }
2765
Felix Held2bb3cdf2018-07-28 00:23:59 +02002766 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002767
2768 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2769 ctrl->timings[channel][slotrank].lanes[lane].falling =
2770 falling_edges[channel][slotrank][lane];
2771 ctrl->timings[channel][slotrank].lanes[lane].rising =
2772 rising_edges[channel][slotrank][lane];
2773 }
2774
2775 FOR_ALL_POPULATED_CHANNELS
2776 program_timings(ctrl, channel);
2777
2778 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002779 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002780 }
2781 return 0;
2782}
2783
2784static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank)
2785{
2786 wait_428c(channel);
2787 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002788 MCHBAR32(0x4220 + 0x400 * channel) = 0x1f006;
2789 MCHBAR32(0x4230 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002790 (MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD)
Felix Held2bb3cdf2018-07-28 00:23:59 +02002791 << 10) | (ctrl->tRCD << 16) | 4;
2792 MCHBAR32(0x4200 + 0x400 * channel) =
2793 (slotrank << 24) | 0x60000;
2794 MCHBAR32(0x4210 + 0x400 * channel) = 0x244;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002795
2796 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002797 MCHBAR32(0x4224 + 0x400 * channel) = 0x1f201;
2798 MCHBAR32(0x4234 + 0x400 * channel) =
2799 0x80011e0 | ((ctrl->tWTR + ctrl->CWL + 8) << 16);
2800 MCHBAR32(0x4204 + 0x400 * channel) = slotrank << 24;
2801 MCHBAR32(0x4214 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002802
2803 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002804 MCHBAR32(0x4228 + 0x400 * channel) = 0x1f105;
2805 MCHBAR32(0x4238 + 0x400 * channel) =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002806 0x40011e0 | (MAX(ctrl->tRTP, 8) << 16);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002807 MCHBAR32(0x4208 + 0x400 * channel) = slotrank << 24;
2808 MCHBAR32(0x4218 + 0x400 * channel) = 0x242;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002809
2810 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002811 MCHBAR32(0x422c + 0x400 * channel) = 0x1f002;
2812 MCHBAR32(0x423c + 0x400 * channel) = 0x1001 | (ctrl->tRP << 16);
2813 MCHBAR32(0x420c + 0x400 * channel) = (slotrank << 24) | 0x60400;
2814 MCHBAR32(0x421c + 0x400 * channel) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002815
Felix Held9cf1dd22018-07-31 14:52:40 +02002816 // execute command queue
2817 MCHBAR32(0x4284 + 0x400 * channel) = RUN_QUEUE_4284(4);
2818
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002819 wait_428c(channel);
2820}
2821
2822int discover_timC_write(ramctr_timing *ctrl)
2823{
2824 const u8 rege3c_b24[3] = { 0, 0xf, 0x2f };
2825 int i, pat;
2826
2827 int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2828 int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES];
2829 int channel, slotrank, lane;
2830
2831 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2832 lower[channel][slotrank][lane] = 0;
2833 upper[channel][slotrank][lane] = MAX_TIMC;
2834 }
2835
Felix Held2bb3cdf2018-07-28 00:23:59 +02002836 MCHBAR32(0x4ea8) = 1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002837 printram("discover timC write:\n");
2838
2839 for (i = 0; i < 3; i++)
2840 FOR_ALL_POPULATED_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002841 MCHBAR32_AND_OR(0xe3c + (channel * 0x100), ~0x3f000000,
2842 rege3c_b24[i] << 24);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002843 udelay(2);
2844 for (pat = 0; pat < NUM_PATTERNS; pat++) {
2845 FOR_ALL_POPULATED_RANKS {
2846 int timC;
2847 u32 raw_statistics[MAX_TIMC + 1];
2848 int statistics[MAX_TIMC + 1];
2849
2850 /* Make sure rn.start < rn.end */
2851 statistics[MAX_TIMC] = 1;
2852
2853 fill_pattern5(ctrl, channel, pat);
Felix Held2bb3cdf2018-07-28 00:23:59 +02002854 MCHBAR32(0x4288 + 0x400 * channel) =
2855 0x1f;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002856 for (timC = 0; timC < MAX_TIMC; timC++) {
2857 FOR_ALL_LANES
2858 ctrl->timings[channel][slotrank].lanes[lane].timC = timC;
2859 program_timings(ctrl, channel);
2860
2861 test_timC_write (ctrl, channel, slotrank);
2862
2863 raw_statistics[timC] =
2864 MCHBAR32(0x436c + 0x400 * channel);
2865 }
2866 FOR_ALL_LANES {
2867 struct run rn;
2868 for (timC = 0; timC < MAX_TIMC; timC++)
2869 statistics[timC] =
2870 !!(raw_statistics[timC] &
2871 (1 << lane));
2872
2873 rn = get_longest_zero_run(statistics,
2874 MAX_TIMC + 1);
2875 if (rn.all) {
2876 printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n",
2877 channel, slotrank, lane);
2878 return MAKE_ERR;
2879 }
2880 printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\n",
2881 channel, slotrank, i, rn.start,
2882 rn.middle, rn.end,
2883 rn.start + ctrl->timC_offset[i],
2884 rn.end - ctrl->timC_offset[i]);
2885 lower[channel][slotrank][lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002886 MAX(rn.start + ctrl->timC_offset[i],
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002887 lower[channel][slotrank][lane]);
2888 upper[channel][slotrank][lane] =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002889 MIN(rn.end - ctrl->timC_offset[i],
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002890 upper[channel][slotrank][lane]);
2891
2892 }
2893 }
2894 }
2895 }
2896
2897 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02002898 MCHBAR32_AND((channel * 0x100) + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002899 udelay(2);
2900 }
2901
Felix Held2bb3cdf2018-07-28 00:23:59 +02002902 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002903
2904 printram("CPB\n");
2905
2906 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
2907 printram("timC %d, %d, %d: %x\n", channel,
2908 slotrank, lane,
2909 (lower[channel][slotrank][lane] +
2910 upper[channel][slotrank][lane]) / 2);
2911 ctrl->timings[channel][slotrank].lanes[lane].timC =
2912 (lower[channel][slotrank][lane] +
2913 upper[channel][slotrank][lane]) / 2;
2914 }
2915 FOR_ALL_POPULATED_CHANNELS {
2916 program_timings(ctrl, channel);
2917 }
2918 return 0;
2919}
2920
2921void normalize_training(ramctr_timing * ctrl)
2922{
2923 int channel, slotrank, lane;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002924 int mat;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002925
2926 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
2927 int delta;
Patrick Rudolph3c8cb972016-11-25 16:00:01 +01002928 mat = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002929 FOR_ALL_LANES mat =
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01002930 MAX(ctrl->timings[channel][slotrank].lanes[lane].timA, mat);
Patrick Rudolph413edc82016-11-25 15:40:07 +01002931 printram("normalize %d, %d, %d: mat %d\n",
2932 channel, slotrank, lane, mat);
2933
2934 delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028;
2935 printram("normalize %d, %d, %d: delta %d\n",
2936 channel, slotrank, lane, delta);
2937
2938 ctrl->timings[channel][slotrank].val_4024 += delta;
2939 ctrl->timings[channel][slotrank].val_4028 += delta;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002940 }
2941
2942 FOR_ALL_POPULATED_CHANNELS {
2943 program_timings(ctrl, channel);
2944 }
2945}
2946
2947void write_controller_mr(ramctr_timing * ctrl)
2948{
2949 int channel, slotrank;
2950
2951 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002952 MCHBAR32(0x0004 + (channel << 8) + lane_registers[slotrank]) =
2953 make_mr0(ctrl, slotrank);
2954 MCHBAR32(0x0008 + (channel << 8) + lane_registers[slotrank]) =
2955 make_mr1(ctrl, slotrank, channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002956 }
2957}
2958
2959int channel_test(ramctr_timing *ctrl)
2960{
2961 int channel, slotrank, lane;
2962
2963 slotrank = 0;
2964 FOR_ALL_POPULATED_CHANNELS
Felix Held2bb3cdf2018-07-28 00:23:59 +02002965 if (MCHBAR32(0x42a0 + (channel << 10)) & 0xa000) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002966 printk(BIOS_EMERG, "Mini channel test failed (1): %d\n",
2967 channel);
2968 return MAKE_ERR;
2969 }
2970 FOR_ALL_POPULATED_CHANNELS {
2971 fill_pattern0(ctrl, channel, 0x12345678, 0x98765432);
2972
Felix Held2bb3cdf2018-07-28 00:23:59 +02002973 MCHBAR32(0x4288 + (channel << 10)) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002974 }
2975
2976 for (slotrank = 0; slotrank < 4; slotrank++)
2977 FOR_ALL_CHANNELS
2978 if (ctrl->rankmap[channel] & (1 << slotrank)) {
2979 FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02002980 MCHBAR32(0x4f40 + 4 * lane) = 0;
2981 MCHBAR32(0x4d40 + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002982 }
2983 wait_428c(channel);
Felix Held9cf1dd22018-07-31 14:52:40 +02002984
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002985 /* DRAM command ACT */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002986 MCHBAR32(0x4220 + (channel << 10)) = 0x0001f006;
2987 MCHBAR32(0x4230 + (channel << 10)) = 0x0028a004;
2988 MCHBAR32(0x4200 + (channel << 10)) =
2989 0x00060000 | (slotrank << 24);
2990 MCHBAR32(0x4210 + (channel << 10)) = 0x00000244;
Felix Held9cf1dd22018-07-31 14:52:40 +02002991
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002992 /* DRAM command WR */
Felix Held2bb3cdf2018-07-28 00:23:59 +02002993 MCHBAR32(0x4224 + (channel << 10)) = 0x0001f201;
2994 MCHBAR32(0x4234 + (channel << 10)) = 0x08281064;
2995 MCHBAR32(0x4204 + (channel << 10)) =
2996 0x00000000 | (slotrank << 24);
2997 MCHBAR32(0x4214 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02002998
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002999 /* DRAM command RD */
Felix Held2bb3cdf2018-07-28 00:23:59 +02003000 MCHBAR32(0x4228 + (channel << 10)) = 0x0001f105;
3001 MCHBAR32(0x4238 + (channel << 10)) = 0x04281064;
3002 MCHBAR32(0x4208 + (channel << 10)) =
3003 0x00000000 | (slotrank << 24);
3004 MCHBAR32(0x4218 + (channel << 10)) = 0x00000242;
Felix Held9cf1dd22018-07-31 14:52:40 +02003005
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003006 /* DRAM command PRE */
Felix Held2bb3cdf2018-07-28 00:23:59 +02003007 MCHBAR32(0x422c + (channel << 10)) = 0x0001f002;
3008 MCHBAR32(0x423c + (channel << 10)) = 0x00280c01;
3009 MCHBAR32(0x420c + (channel << 10)) =
3010 0x00060400 | (slotrank << 24);
3011 MCHBAR32(0x421c + (channel << 10)) = 0x00000240;
Felix Held9cf1dd22018-07-31 14:52:40 +02003012
3013 // execute command queue
3014 MCHBAR32(0x4284 + (channel << 10)) = RUN_QUEUE_4284(4);
3015
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003016 wait_428c(channel);
3017 FOR_ALL_LANES
Felix Held2bb3cdf2018-07-28 00:23:59 +02003018 if (MCHBAR32(0x4340 + (channel << 10) + 4 * lane)) {
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003019 printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n",
3020 channel, slotrank, lane);
3021 return MAKE_ERR;
3022 }
3023 }
3024 return 0;
3025}
3026
3027void set_scrambling_seed(ramctr_timing * ctrl)
3028{
3029 int channel;
3030
3031 /* FIXME: we hardcode seeds. Do we need to use some PRNG for them?
3032 I don't think so. */
3033 static u32 seeds[NUM_CHANNELS][3] = {
3034 {0x00009a36, 0xbafcfdcf, 0x46d1ab68},
3035 {0x00028bfa, 0x53fe4b49, 0x19ed5483}
3036 };
3037 FOR_ALL_POPULATED_CHANNELS {
3038 MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000;
Arthur Heymans6af8aab2017-09-26 23:18:14 +02003039 MCHBAR32(0x4034 + 0x400 * channel) = seeds[channel][0];
3040 MCHBAR32(0x403c + 0x400 * channel) = seeds[channel][1];
3041 MCHBAR32(0x4038 + 0x400 * channel) = seeds[channel][2];
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003042 }
3043}
3044
3045void set_4f8c(void)
3046{
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003047 u32 cpu;
3048
Subrata Banik53b08c32018-12-10 14:11:35 +05303049 cpu = cpu_get_cpuid();
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003050 if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) {
3051 MCHBAR32(0x4f8c) = 0x141D1519;
3052 } else {
3053 MCHBAR32(0x4f8c) = 0x551D1519;
3054 }
3055}
3056
3057void prepare_training(ramctr_timing * ctrl)
3058{
3059 int channel;
3060
3061 FOR_ALL_POPULATED_CHANNELS {
3062 // Always drive command bus
Felix Held9fe248f2018-07-31 20:59:45 +02003063 MCHBAR32_OR(0x4004 + 0x400 * channel, 0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003064 }
3065
3066 udelay(1);
3067
3068 FOR_ALL_POPULATED_CHANNELS {
3069 wait_428c(channel);
3070 }
3071}
3072
3073void set_4008c(ramctr_timing * ctrl)
3074{
3075 int channel, slotrank;
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003076
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003077 FOR_ALL_POPULATED_CHANNELS {
3078 u32 b20, b4_8_12;
3079 int min_320c = 10000;
3080 int max_320c = -10000;
3081
3082 FOR_ALL_POPULATED_RANKS {
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01003083 max_320c = MAX(ctrl->timings[channel][slotrank].val_320c, max_320c);
3084 min_320c = MIN(ctrl->timings[channel][slotrank].val_320c, min_320c);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003085 }
3086
3087 if (max_320c - min_320c > 51)
3088 b20 = 0;
3089 else
3090 b20 = ctrl->ref_card_offset[channel];
3091
3092 if (ctrl->reg_320c_range_threshold < max_320c - min_320c)
3093 b4_8_12 = 0x3330;
3094 else
3095 b4_8_12 = 0x2220;
3096
Patrick Rudolph19c3dad2016-11-26 11:37:45 +01003097 dram_odt_stretch(ctrl, channel);
3098
Felix Held2bb3cdf2018-07-28 00:23:59 +02003099 MCHBAR32(0x4008 + (channel << 10)) =
Felix Held2463aa92018-07-29 21:37:55 +02003100 0x0a000000 | (b20 << 20) |
3101 ((ctrl->ref_card_offset[channel] + 2) << 16) | b4_8_12;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003102 }
3103}
3104
3105void set_42a0(ramctr_timing * ctrl)
3106{
3107 int channel;
3108 FOR_ALL_POPULATED_CHANNELS {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003109 MCHBAR32(0x42a0 + 0x400 * channel) =
3110 0x00001000 | ctrl->rankmap[channel];
Felix Held2463aa92018-07-29 21:37:55 +02003111 MCHBAR32_AND(0x4004 + 0x400 * channel, ~0x20000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003112 }
3113}
3114
3115static int encode_5d10(int ns)
3116{
3117 return (ns + 499) / 500;
3118}
3119
3120/* FIXME: values in this function should be hardware revision-dependent. */
3121void final_registers(ramctr_timing * ctrl)
3122{
Patrick Rudolph74203de2017-11-20 11:57:01 +01003123 const size_t is_mobile = get_platform_type() == PLATFORM_MOBILE;
3124
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003125 int channel;
3126 int t1_cycles = 0, t1_ns = 0, t2_ns;
3127 int t3_ns;
3128 u32 r32;
3129
Felix Held2bb3cdf2018-07-28 00:23:59 +02003130 MCHBAR32(0x4cd4) = 0x00000046;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003131
Felix Heldf9b826a2018-07-30 17:56:52 +02003132 FOR_ALL_CHANNELS
3133 MCHBAR32_AND_OR(0x400c + 0x400 * channel, 0xFFFFCFFF, 0x1000);
Patrick Rudolph652c4912017-10-31 11:36:55 +01003134
Patrick Rudolph74203de2017-11-20 11:57:01 +01003135 if (is_mobile)
Patrick Rudolph652c4912017-10-31 11:36:55 +01003136 /* APD - DLL Off, 64 DCLKs until idle, decision per rank */
3137 MCHBAR32(PM_PDWN_Config) = 0x00000740;
3138 else
3139 /* APD - PPD, 64 DCLKs until idle, decision per rank */
3140 MCHBAR32(PM_PDWN_Config) = 0x00000340;
3141
Felix Heldf9b826a2018-07-30 17:56:52 +02003142 FOR_ALL_CHANNELS
3143 MCHBAR32(0x4380 + 0x400 * channel) = 0x00000aaa;
3144
Felix Held2bb3cdf2018-07-28 00:23:59 +02003145 MCHBAR32(0x4f88) = 0x5f7003ff; // OK
3146 MCHBAR32(0x5064) = 0x00073000 | ctrl->reg_5064b0; // OK
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003147
3148 FOR_ALL_CHANNELS {
3149 switch (ctrl->rankmap[channel]) {
3150 /* Unpopulated channel. */
3151 case 0:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003152 MCHBAR32(0x4384 + channel * 0x400) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003153 break;
3154 /* Only single-ranked dimms. */
3155 case 1:
3156 case 4:
3157 case 5:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003158 MCHBAR32(0x4384 + channel * 0x400) = 0x373131;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003159 break;
3160 /* Dual-ranked dimms present. */
3161 default:
Felix Held2bb3cdf2018-07-28 00:23:59 +02003162 MCHBAR32(0x4384 + channel * 0x400) = 0x9b6ea1;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003163 break;
3164 }
3165 }
3166
Felix Held50b7ed22019-12-30 20:41:54 +01003167 MCHBAR32(MEM_TRML_ESTIMATION_CONFIG) = 0xca9171e5;
3168 MCHBAR32_AND_OR(MEM_TRML_THRESHOLDS_CONFIG, ~0xffffff, 0xe4d5d0);
3169 MCHBAR32_AND(MEM_TRML_INTERRUPT, ~0x1f);
Felix Heldf9b826a2018-07-30 17:56:52 +02003170
3171 FOR_ALL_CHANNELS
Felix Helddee167e2019-12-30 17:30:16 +01003172 MCHBAR32_AND_OR(TC_RFP_C0 + 0x400 * channel, ~0x30000, 1 << 16);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003173
Felix Held9fe248f2018-07-31 20:59:45 +02003174 MCHBAR32_OR(0x5030, 1);
3175 MCHBAR32_OR(0x5030, 0x80);
Felix Held2463aa92018-07-29 21:37:55 +02003176 MCHBAR32(0x5f18) = 0xfa;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003177
3178 /* Find a populated channel. */
3179 FOR_ALL_POPULATED_CHANNELS
3180 break;
3181
Felix Held2bb3cdf2018-07-28 00:23:59 +02003182 t1_cycles = (MCHBAR32(0x4290 + channel * 0x400) >> 8) & 0xff;
3183 r32 = MCHBAR32(0x5064);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003184 if (r32 & 0x20000)
3185 t1_cycles += (r32 & 0xfff);
Felix Held2bb3cdf2018-07-28 00:23:59 +02003186 t1_cycles += MCHBAR32(channel * 0x400 + 0x42a4) & 0xfff;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003187 t1_ns = t1_cycles * ctrl->tCK / 256 + 544;
3188 if (!(r32 & 0x20000))
3189 t1_ns += 500;
3190
Felix Held2bb3cdf2018-07-28 00:23:59 +02003191 t2_ns = 10 * ((MCHBAR32(0x5f10) >> 8) & 0xfff);
3192 if (MCHBAR32(0x5f00) & 8)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003193 {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003194 t3_ns = 10 * ((MCHBAR32(0x5f20) >> 8) & 0xfff);
3195 t3_ns += 10 * (MCHBAR32(0x5f18) & 0xff);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003196 }
3197 else
3198 {
3199 t3_ns = 500;
3200 }
3201 printk(BIOS_DEBUG, "t123: %d, %d, %d\n",
3202 t1_ns, t2_ns, t3_ns);
Felix Heldb802c072018-07-29 21:46:19 +02003203 MCHBAR32_AND_OR(0x5d10, 0xC0C0C0C0,
3204 ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) |
Felix Held2bb3cdf2018-07-28 00:23:59 +02003205 (encode_5d10(t1_ns) << 8) | ((encode_5d10(t3_ns) +
Felix Heldb802c072018-07-29 21:46:19 +02003206 encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) | 0xc);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003207}
3208
3209void restore_timings(ramctr_timing * ctrl)
3210{
3211 int channel, slotrank, lane;
3212
3213 FOR_ALL_POPULATED_CHANNELS
3214 MCHBAR32(0x4004 + 0x400 * channel) =
3215 ctrl->tRRD
3216 | (ctrl->tRTP << 4)
3217 | (ctrl->tCKE << 8)
3218 | (ctrl->tWTR << 12)
3219 | (ctrl->tFAW << 16)
3220 | (ctrl->tWR << 24)
3221 | (ctrl->cmd_stretch[channel] << 30);
3222
3223 udelay(1);
3224
3225 FOR_ALL_POPULATED_CHANNELS {
3226 wait_428c(channel);
3227 }
3228
3229 FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES {
Felix Held2bb3cdf2018-07-28 00:23:59 +02003230 MCHBAR32(0x4080 + 0x400 * channel + 4 * lane) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003231 }
3232
3233 FOR_ALL_POPULATED_CHANNELS
Felix Held2463aa92018-07-29 21:37:55 +02003234 MCHBAR32_OR(0x4008 + 0x400 * channel, 0x8000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003235
3236 FOR_ALL_POPULATED_CHANNELS {
3237 udelay (1);
Felix Held2463aa92018-07-29 21:37:55 +02003238 MCHBAR32_OR(0x4020 + 0x400 * channel, 0x200000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003239 }
3240
3241 printram("CPE\n");
3242
Felix Held2bb3cdf2018-07-28 00:23:59 +02003243 MCHBAR32(0x3400) = 0;
3244 MCHBAR32(0x4eb0) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003245
3246 printram("CP5b\n");
3247
3248 FOR_ALL_POPULATED_CHANNELS {
3249 program_timings(ctrl, channel);
3250 }
3251
3252 u32 reg, addr;
3253
3254 while (!(MCHBAR32(0x5084) & 0x10000));
3255 do {
3256 reg = MCHBAR32(0x428c);
3257 } while ((reg & 0x14) == 0);
3258
3259 // Set state of memory controller
3260 MCHBAR32(0x5030) = 0x116;
3261 MCHBAR32(0x4ea0) = 0;
3262
3263 // Wait 500us
3264 udelay(500);
3265
3266 FOR_ALL_CHANNELS {
3267 // Set valid rank CKE
3268 reg = 0;
3269 reg = (reg & ~0xf) | ctrl->rankmap[channel];
3270 addr = 0x400 * channel + 0x42a0;
3271 MCHBAR32(addr) = reg;
3272
3273 // Wait 10ns for ranks to settle
3274 //udelay(0.01);
3275
3276 reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4);
3277 MCHBAR32(addr) = reg;
3278
3279 // Write reset using a NOP
3280 write_reset(ctrl);
3281 }
3282
3283 /* mrs commands. */
3284 dram_mrscommands(ctrl);
3285
3286 printram("CP5c\n");
3287
Felix Held2bb3cdf2018-07-28 00:23:59 +02003288 MCHBAR32(0x3000) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003289
3290 FOR_ALL_CHANNELS {
Felix Held2463aa92018-07-29 21:37:55 +02003291 MCHBAR32_AND(channel * 0x100 + 0xe3c, ~0x3f000000);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003292 udelay(2);
3293 }
3294
Felix Held2bb3cdf2018-07-28 00:23:59 +02003295 MCHBAR32(0x4ea8) = 0;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01003296}