blob: 12d49d83780d1d367105b62287031a4210271f8d [file] [log] [blame]
David Hendricks2004b932018-03-09 13:58:27 -08001/***********************license start***********************************
2* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
3* reserved.
4*
5*
6* Redistribution and use in source and binary forms, with or without
7* modification, are permitted provided that the following conditions are
8* met:
9*
10* * Redistributions of source code must retain the above copyright
11* notice, this list of conditions and the following disclaimer.
12*
13* * Redistributions in binary form must reproduce the above
14* copyright notice, this list of conditions and the following
15* disclaimer in the documentation and/or other materials provided
16* with the distribution.
17*
18* * Neither the name of Cavium Inc. nor the names of
19* its contributors may be used to endorse or promote products
20* derived from this software without specific prior written
21* permission.
22*
23* This Software, including technical data, may be subject to U.S. export
24* control laws, including the U.S. Export Administration Act and its
25* associated regulations, and may be subject to export or import
26* regulations in other countries.
27*
28* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38***********************license end**************************************/
39#include <bdk.h>
Martin Rothdcf52c82018-11-26 18:40:43 -070040#include <bdk-coreboot.h>
David Hendricks2004b932018-03-09 13:58:27 -080041#include "libbdk-arch/bdk-csrs-l2c_tad.h"
42#include "libbdk-arch/bdk-csrs-mio_fus.h"
43#include "dram-internal.h"
44
David Hendricks7d48ac52018-03-09 14:30:38 -080045#include <stdlib.h>
46#include <string.h>
47#include <libbdk-hal/bdk-config.h>
48#include <libbdk-hal/bdk-l2c.h>
49#include <libbdk-hal/bdk-rng.h>
50#include <libbdk-trust/bdk-trust.h>
51#include <lame_string.h>
52
David Hendricks2004b932018-03-09 13:58:27 -080053#define WODT_MASK_2R_1S 1 // FIXME: did not seem to make much difference with #152 1-slot?
54
55#define DESKEW_RODT_CTL 1
56
57// Set to 1 to use the feature whenever possible automatically.
58// When 0, however, the feature is still available, and it can
59// be enabled via envvar override "ddr_enable_write_deskew=1".
60#define ENABLE_WRITE_DESKEW_DEFAULT 0
61
62#define ENABLE_COMPUTED_VREF_ADJUSTMENT 1
63
64#define RLEXTRAS_PATCH 1 // write to unused RL rank entries
65#define WLEXTRAS_PATCH 1 // write to unused WL rank entries
66#define ADD_48_OHM_SKIP 1
67#define NOSKIP_40_48_OHM 1
68#define NOSKIP_48_STACKED 1
69#define NOSKIP_FOR_MINI 1
70#define NOSKIP_FOR_2S_1R 1
71#define MAJORITY_OVER_AVG 1
72#define RANK_MAJORITY MAJORITY_OVER_AVG && 1
73#define SW_WL_CHECK_PATCH 1 // check validity after SW adjust
74#define HW_WL_MAJORITY 1
75#define SWL_TRY_HWL_ALT HW_WL_MAJORITY && 1 // try HW WL base alternate if available when SW WL fails
76#define DISABLE_SW_WL_PASS_2 1
77
78#define HWL_BY_BYTE 0 // FIXME? set to 1 to do HWL a byte at a time (seemed to work better earlier?)
79
80#define USE_ORIG_TEST_DRAM_BYTE 1
81
82// collect and print LMC utilization using SWL software algorithm
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +010083#define ENABLE_SW_WLEVEL_UTILIZATION 0
David Hendricks2004b932018-03-09 13:58:27 -080084
85#define COUNT_RL_CANDIDATES 1
86
87#define LOOK_FOR_STUCK_BYTE 0
88#define ENABLE_STUCK_BYTE_RESET 0
89
90#define FAILSAFE_CHECK 1
91
92#define PERFECT_BITMASK_COUNTING 1
93
94#define DAC_OVERRIDE_EARLY 1
95
96#define SWL_WITH_HW_ALTS_CHOOSE_SW 0 // FIXME: allow override?
97
98#define DEBUG_VALIDATE_BITMASK 0
99#if DEBUG_VALIDATE_BITMASK
100#define debug_bitmask_print ddr_print
101#else
102#define debug_bitmask_print(...)
103#endif
104
105#define ENABLE_SLOT_CTL_ACCESS 0
106#undef ENABLE_CUSTOM_RLEVEL_TABLE
107
108#define ENABLE_DISPLAY_MPR_PAGE 0
109#if ENABLE_DISPLAY_MPR_PAGE
110static void Display_MPR_Page_Location(bdk_node_t node, int rank,
111 int ddr_interface_num, int dimm_count,
112 int page, int location, uint64_t *mpr_data);
113#endif
114
115#define USE_L2_WAYS_LIMIT 1
116
117/* Read out Deskew Settings for DDR */
118
119typedef struct {
120 uint16_t bits[8];
121} deskew_bytes_t;
122typedef struct {
123 deskew_bytes_t bytes[9];
124} deskew_data_t;
125
126static void
127Get_Deskew_Settings(bdk_node_t node, int ddr_interface_num, deskew_data_t *dskdat)
128{
129 bdk_lmcx_phy_ctl_t phy_ctl;
130 bdk_lmcx_config_t lmc_config;
131 int bit_num, bit_index;
132 int byte_lane, byte_limit;
133 // NOTE: these are for pass 2.x
134 int is_t88p2 = !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X); // added 81xx and 83xx
135 int bit_end = (is_t88p2) ? 9 : 8;
136
137 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
138 byte_limit = ((lmc_config.s.mode32b) ? 4 : 8) + lmc_config.s.ecc_ena;
139
140 memset(dskdat, 0, sizeof(*dskdat));
141
David Hendricks7d48ac52018-03-09 14:30:38 -0800142 BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
143 _phy_ctl.s.dsk_dbg_clk_scaler = 3);
David Hendricks2004b932018-03-09 13:58:27 -0800144
145 for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
146 bit_index = 0;
David Hendricks7d48ac52018-03-09 14:30:38 -0800147 for (bit_num = 0; bit_num <= bit_end; ++bit_num) { // NOTE: this is for pass 2.x
David Hendricks2004b932018-03-09 13:58:27 -0800148
David Hendricks7d48ac52018-03-09 14:30:38 -0800149 if (bit_num == 4) continue;
150 if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
David Hendricks2004b932018-03-09 13:58:27 -0800151
152 // set byte lane and bit to read
David Hendricks7d48ac52018-03-09 14:30:38 -0800153 BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
154 (_phy_ctl.s.dsk_dbg_bit_sel = bit_num,
155 _phy_ctl.s.dsk_dbg_byte_sel = byte_lane));
David Hendricks2004b932018-03-09 13:58:27 -0800156
157 // start read sequence
David Hendricks7d48ac52018-03-09 14:30:38 -0800158 BDK_CSR_MODIFY(_phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
159 _phy_ctl.s.dsk_dbg_rd_start = 1);
David Hendricks2004b932018-03-09 13:58:27 -0800160
161 // poll for read sequence to complete
162 do {
163 phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
164 } while (phy_ctl.s.dsk_dbg_rd_complete != 1);
David Hendricks7d48ac52018-03-09 14:30:38 -0800165
David Hendricks2004b932018-03-09 13:58:27 -0800166 // record the data
167 dskdat->bytes[byte_lane].bits[bit_index] = phy_ctl.s.dsk_dbg_rd_data & 0x3ff;
168 bit_index++;
169
170 } /* for (bit_num = 0; bit_num <= bit_end; ++bit_num) */
171 } /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
David Hendricks7d48ac52018-03-09 14:30:38 -0800172
David Hendricks2004b932018-03-09 13:58:27 -0800173 return;
174}
175
176static void
177Display_Deskew_Data(bdk_node_t node, int ddr_interface_num,
178 deskew_data_t *dskdat, int print_enable)
179{
180 int byte_lane;
181 int bit_num;
182 uint16_t flags, deskew;
183 bdk_lmcx_config_t lmc_config;
184 int byte_limit;
185 const char *fc = " ?-=+*#&";
186
187 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
188 byte_limit = ((lmc_config.s.mode32b) ? 4 : 8) + lmc_config.s.ecc_ena;
189
190 if (print_enable) {
191 VB_PRT(print_enable, "N%d.LMC%d: Deskew Data: Bit => :",
192 node, ddr_interface_num);
David Hendricks7d48ac52018-03-09 14:30:38 -0800193 for (bit_num = 7; bit_num >= 0; --bit_num)
David Hendricks2004b932018-03-09 13:58:27 -0800194 VB_PRT(print_enable, " %3d ", bit_num);
195 VB_PRT(print_enable, "\n");
196 }
197
198 for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
199 if (print_enable)
200 VB_PRT(print_enable, "N%d.LMC%d: Bit Deskew Byte %d %s :",
201 node, ddr_interface_num, byte_lane,
202 (print_enable >= VBL_TME) ? "FINAL" : " ");
203
204 for (bit_num = 7; bit_num >= 0; --bit_num) {
205
David Hendricks7d48ac52018-03-09 14:30:38 -0800206 flags = dskdat->bytes[byte_lane].bits[bit_num] & 7;
207 deskew = dskdat->bytes[byte_lane].bits[bit_num] >> 3;
David Hendricks2004b932018-03-09 13:58:27 -0800208
209 if (print_enable)
210 VB_PRT(print_enable, " %3d %c", deskew, fc[flags^1]);
211
212 } /* for (bit_num = 7; bit_num >= 0; --bit_num) */
213
214 if (print_enable)
215 VB_PRT(print_enable, "\n");
216
217 } /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
David Hendricks7d48ac52018-03-09 14:30:38 -0800218
David Hendricks2004b932018-03-09 13:58:27 -0800219 return;
220}
221
222static int
223change_wr_deskew_ena(bdk_node_t node, int ddr_interface_num, int new_state)
224{
225 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
226 int saved_wr_deskew_ena;
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100227
David Hendricks2004b932018-03-09 13:58:27 -0800228 // return original WR_DESKEW_ENA setting
229 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
230 saved_wr_deskew_ena = !!GET_DDR_DLL_CTL3(wr_deskew_ena);
231 if (saved_wr_deskew_ena != !!new_state) { // write it only when changing it
232 SET_DDR_DLL_CTL3(wr_deskew_ena, !!new_state);
233 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
234 }
235 return saved_wr_deskew_ena;
236}
237
238typedef struct {
239 int saturated; // number saturated
240 int unlocked; // number unlocked
241 int nibrng_errs; // nibble range errors
242 int nibunl_errs; // nibble unlocked errors
243 //int nibsat_errs; // nibble saturation errors
244 int bitval_errs; // bit value errors
245#if LOOK_FOR_STUCK_BYTE
246 int bytes_stuck; // byte(s) stuck
247#endif
248} deskew_counts_t;
249
250#define MIN_BITVAL 17
251#define MAX_BITVAL 110
252
253static deskew_counts_t deskew_training_results;
254static int deskew_validation_delay = 10000; // FIXME: make this a var for overriding
255
256static void
257Validate_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_num,
258 deskew_counts_t *counts, int print_enable)
259{
260 int byte_lane, bit_num, nib_num;
261 int nibrng_errs, nibunl_errs, bitval_errs;
262 //int nibsat_errs;
263 bdk_lmcx_config_t lmc_config;
264 int16_t nib_min[2], nib_max[2], nib_unl[2]/*, nib_sat[2]*/;
265 // NOTE: these are for pass 2.x
266 int is_t88p2 = !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X); // added 81xx and 83xx
267 int bit_start = (is_t88p2) ? 9 : 8;
268 int byte_limit;
269#if LOOK_FOR_STUCK_BYTE
270 uint64_t bl_mask[2]; // enough for 128 values
271 int bit_values;
272#endif
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100273 deskew_data_t dskdat;
David Hendricks2004b932018-03-09 13:58:27 -0800274 int bit_index;
275 int16_t flags, deskew;
276 const char *fc = " ?-=+*#&";
277 int saved_wr_deskew_ena;
278 int bit_last;
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100279
David Hendricks2004b932018-03-09 13:58:27 -0800280 // save original WR_DESKEW_ENA setting, and disable it for read deskew
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100281 saved_wr_deskew_ena = change_wr_deskew_ena(node, ddr_interface_num, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800282
283 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
284 byte_limit = ((!lmc_config.s.mode32b) ? 8 : 4) + lmc_config.s.ecc_ena;
285
286 memset(counts, 0, sizeof(deskew_counts_t));
287
288 Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
289
290 if (print_enable) {
291 VB_PRT(print_enable, "N%d.LMC%d: Deskew Settings: Bit => :",
292 node, ddr_interface_num);
David Hendricks7d48ac52018-03-09 14:30:38 -0800293 for (bit_num = 7; bit_num >= 0; --bit_num)
David Hendricks2004b932018-03-09 13:58:27 -0800294 VB_PRT(print_enable, " %3d ", bit_num);
295 VB_PRT(print_enable, "\n");
296 }
297
298 for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
299 if (print_enable)
300 VB_PRT(print_enable, "N%d.LMC%d: Bit Deskew Byte %d %s :",
301 node, ddr_interface_num, byte_lane,
302 (print_enable >= VBL_TME) ? "FINAL" : " ");
303
David Hendricks7d48ac52018-03-09 14:30:38 -0800304 nib_min[0] = 127; nib_min[1] = 127;
305 nib_max[0] = 0; nib_max[1] = 0;
306 nib_unl[0] = 0; nib_unl[1] = 0;
307 //nib_sat[0] = 0; nib_sat[1] = 0;
David Hendricks2004b932018-03-09 13:58:27 -0800308
309#if LOOK_FOR_STUCK_BYTE
310 bl_mask[0] = bl_mask[1] = 0;
311#endif
312
313 if ((lmc_config.s.mode32b == 1) && (byte_lane == 4)) {
314 bit_index = 3;
315 bit_last = 3;
316 if (print_enable)
317 VB_PRT(print_enable, " ");
318 } else {
319 bit_index = 7;
320 bit_last = bit_start;
321 }
322
David Hendricks7d48ac52018-03-09 14:30:38 -0800323 for (bit_num = bit_last; bit_num >= 0; --bit_num) { // NOTE: this is for pass 2.x
324 if (bit_num == 4) continue;
325 if ((bit_num == 5) && is_t88p2) continue; // NOTE: this is for pass 2.x
David Hendricks2004b932018-03-09 13:58:27 -0800326
David Hendricks7d48ac52018-03-09 14:30:38 -0800327 nib_num = (bit_num > 4) ? 1 : 0;
David Hendricks2004b932018-03-09 13:58:27 -0800328
David Hendricks7d48ac52018-03-09 14:30:38 -0800329 flags = dskdat.bytes[byte_lane].bits[bit_index] & 7;
330 deskew = dskdat.bytes[byte_lane].bits[bit_index] >> 3;
David Hendricks2004b932018-03-09 13:58:27 -0800331 bit_index--;
332
333 counts->saturated += !!(flags & 6);
334 counts->unlocked += !(flags & 1);
335
336 nib_unl[nib_num] += !(flags & 1);
337 //nib_sat[nib_num] += !!(flags & 6);
338
339 if (flags & 1) { // FIXME? only do range when locked
340 nib_min[nib_num] = min(nib_min[nib_num], deskew);
341 nib_max[nib_num] = max(nib_max[nib_num], deskew);
342 }
343
344#if LOOK_FOR_STUCK_BYTE
345 bl_mask[(deskew >> 6) & 1] |= 1UL << (deskew & 0x3f);
346#endif
347
348 if (print_enable)
349 VB_PRT(print_enable, " %3d %c", deskew, fc[flags^1]);
350
351 } /* for (bit_num = bit_last; bit_num >= 0; --bit_num) */
352
David Hendricks7d48ac52018-03-09 14:30:38 -0800353 /*
David Hendricks2004b932018-03-09 13:58:27 -0800354 Now look for nibble errors:
355
David Hendricks7d48ac52018-03-09 14:30:38 -0800356 For bit 55, it looks like a bit deskew problem. When the upper nibble of byte 6
357 needs to go to saturation, bit 7 of byte 6 locks prematurely at 64.
358 For DIMMs with raw card A and B, can we reset the deskew training when we encounter this case?
359 The reset criteria should be looking at one nibble at a time for raw card A and B;
360 if the bit-deskew setting within a nibble is different by > 33, we'll issue a reset
361 to the bit deskew training.
David Hendricks2004b932018-03-09 13:58:27 -0800362
David Hendricks7d48ac52018-03-09 14:30:38 -0800363 LMC0 Bit Deskew Byte(6): 64 0 - 0 - 0 - 26 61 35 64
364 */
365 // upper nibble range, then lower nibble range
366 nibrng_errs = ((nib_max[1] - nib_min[1]) > 33) ? 1 : 0;
367 nibrng_errs |= ((nib_max[0] - nib_min[0]) > 33) ? 1 : 0;
David Hendricks2004b932018-03-09 13:58:27 -0800368
David Hendricks7d48ac52018-03-09 14:30:38 -0800369 // check for nibble all unlocked
370 nibunl_errs = ((nib_unl[0] == 4) || (nib_unl[1] == 4)) ? 1 : 0;
David Hendricks2004b932018-03-09 13:58:27 -0800371
David Hendricks7d48ac52018-03-09 14:30:38 -0800372 // check for nibble all saturated
373 //nibsat_errs = ((nib_sat[0] == 4) || (nib_sat[1] == 4)) ? 1 : 0;
374
375 // check for bit value errors, ie < 17 or > 110
David Hendricks2004b932018-03-09 13:58:27 -0800376 // FIXME? assume max always > MIN_BITVAL and min < MAX_BITVAL
David Hendricks7d48ac52018-03-09 14:30:38 -0800377 bitval_errs = ((nib_max[1] > MAX_BITVAL) || (nib_max[0] > MAX_BITVAL)) ? 1 : 0;
378 bitval_errs |= ((nib_min[1] < MIN_BITVAL) || (nib_min[0] < MIN_BITVAL)) ? 1 : 0;
379
380 if (((nibrng_errs != 0) || (nibunl_errs != 0) /*|| (nibsat_errs != 0)*/ || (bitval_errs != 0))
David Hendricks2004b932018-03-09 13:58:27 -0800381 && print_enable)
382 {
David Hendricks7d48ac52018-03-09 14:30:38 -0800383 VB_PRT(print_enable, " %c%c%c%c",
David Hendricks2004b932018-03-09 13:58:27 -0800384 (nibrng_errs)?'R':' ',
385 (nibunl_errs)?'U':' ',
386 (bitval_errs)?'V':' ',
387 /*(nibsat_errs)?'S':*/' ');
David Hendricks7d48ac52018-03-09 14:30:38 -0800388 }
David Hendricks2004b932018-03-09 13:58:27 -0800389
390#if LOOK_FOR_STUCK_BYTE
391 bit_values = __builtin_popcountl(bl_mask[0]) + __builtin_popcountl(bl_mask[1]);
392 if (bit_values < 3) {
393 counts->bytes_stuck |= (1 << byte_lane);
394 if (print_enable)
395 VB_PRT(print_enable, "X");
396 }
397#endif
398 if (print_enable)
399 VB_PRT(print_enable, "\n");
400
David Hendricks7d48ac52018-03-09 14:30:38 -0800401 counts->nibrng_errs |= (nibrng_errs << byte_lane);
402 counts->nibunl_errs |= (nibunl_errs << byte_lane);
403 //counts->nibsat_errs |= (nibsat_errs << byte_lane);
404 counts->bitval_errs |= (bitval_errs << byte_lane);
David Hendricks2004b932018-03-09 13:58:27 -0800405
406#if LOOK_FOR_STUCK_BYTE
407 // just for completeness, allow print of the stuck values bitmask after the bytelane print
408 if ((bit_values < 3) && print_enable) {
409 VB_PRT(VBL_DEV, "N%d.LMC%d: Deskew byte %d STUCK on value 0x%016lx.%016lx\n",
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100410 node, ddr_interface_num, byte_lane,
David Hendricks2004b932018-03-09 13:58:27 -0800411 bl_mask[1], bl_mask[0]);
412 }
413#endif
414
415 } /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
David Hendricks7d48ac52018-03-09 14:30:38 -0800416
David Hendricks2004b932018-03-09 13:58:27 -0800417 // restore original WR_DESKEW_ENA setting
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100418 change_wr_deskew_ena(node, ddr_interface_num, saved_wr_deskew_ena);
David Hendricks2004b932018-03-09 13:58:27 -0800419
420 return;
421}
422
423unsigned short load_dac_override(int node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -0800424 int dac_value, int byte)
David Hendricks2004b932018-03-09 13:58:27 -0800425{
426 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
427 int bytex = (byte == 0x0A) ? byte : byte + 1; // single bytelanes incr by 1; A is for ALL
428
429 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
430
431 SET_DDR_DLL_CTL3(byte_sel, bytex);
432 SET_DDR_DLL_CTL3(offset, dac_value >> 1); // only 7-bit field, use MS bits
433
434 ddr_dll_ctl3.s.bit_select = 0x9; /* No-op */
435 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100436
David Hendricks2004b932018-03-09 13:58:27 -0800437 ddr_dll_ctl3.s.bit_select = 0xC; /* Vref bypass setting load */
438 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100439
David Hendricks2004b932018-03-09 13:58:27 -0800440 ddr_dll_ctl3.s.bit_select = 0xD; /* Vref bypass on. */
441 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100442
David Hendricks2004b932018-03-09 13:58:27 -0800443 ddr_dll_ctl3.s.bit_select = 0x9; /* No-op */
444 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
445
446 return ((unsigned short) GET_DDR_DLL_CTL3(offset));
447}
448
449// arg dac_or_dbi is 1 for DAC, 0 for DBI
450// returns 9 entries (bytelanes 0 through 8) in settings[]
451// returns 0 if OK, -1 if a problem
452int read_DAC_DBI_settings(int node, int ddr_interface_num,
453 int dac_or_dbi, int *settings)
454{
455 bdk_lmcx_phy_ctl_t phy_ctl;
456 int byte_lane, bit_num;
457 int deskew;
458 int dac_value;
459 int is_t88p2 = !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X); // added 81xx and 83xx
460
461 phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
462 phy_ctl.s.dsk_dbg_clk_scaler = 3;
463 DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), phy_ctl.u);
464
465 bit_num = (dac_or_dbi) ? 4 : 5;
466 if ((bit_num == 5) && !is_t88p2) { // NOTE: this is for pass 1.x
David Hendricks7d48ac52018-03-09 14:30:38 -0800467 return -1;
David Hendricks2004b932018-03-09 13:58:27 -0800468 }
469
470 for (byte_lane = 8; byte_lane >= 0 ; --byte_lane) { // FIXME: always assume ECC is available
471
David Hendricks7d48ac52018-03-09 14:30:38 -0800472 //set byte lane and bit to read
David Hendricks2004b932018-03-09 13:58:27 -0800473 phy_ctl.s.dsk_dbg_bit_sel = bit_num;
474 phy_ctl.s.dsk_dbg_byte_sel = byte_lane;
475 DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), phy_ctl.u);
476
David Hendricks7d48ac52018-03-09 14:30:38 -0800477 //start read sequence
David Hendricks2004b932018-03-09 13:58:27 -0800478 phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
479 phy_ctl.s.dsk_dbg_rd_start = 1;
480 DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), phy_ctl.u);
481
David Hendricks7d48ac52018-03-09 14:30:38 -0800482 //poll for read sequence to complete
483 do {
484 phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
485 } while (phy_ctl.s.dsk_dbg_rd_complete != 1);
David Hendricks2004b932018-03-09 13:58:27 -0800486
David Hendricks7d48ac52018-03-09 14:30:38 -0800487 deskew = phy_ctl.s.dsk_dbg_rd_data /*>> 3*/; // leave the flag bits for DBI
488 dac_value = phy_ctl.s.dsk_dbg_rd_data & 0xff;
489
490 settings[byte_lane] = (dac_or_dbi) ? dac_value : deskew;
David Hendricks2004b932018-03-09 13:58:27 -0800491
492 } /* for (byte_lane = 8; byte_lane >= 0 ; --byte_lane) { */
493
494 return 0;
495}
496
497// print out the DBI settings array
498// arg dac_or_dbi is 1 for DAC, 0 for DBI
499void
500display_DAC_DBI_settings(int node, int lmc, int dac_or_dbi,
David Hendricks7d48ac52018-03-09 14:30:38 -0800501 int ecc_ena, int *settings, const char *title)
David Hendricks2004b932018-03-09 13:58:27 -0800502{
503 int byte;
504 int flags;
505 int deskew;
506 const char *fc = " ?-=+*#&";
507
508 ddr_print("N%d.LMC%d: %s %s Deskew Settings %d:0 :",
509 node, lmc, title, (dac_or_dbi)?"DAC":"DBI", 7+ecc_ena);
510 for (byte = (7+ecc_ena); byte >= 0; --byte) { // FIXME: what about 32-bit mode?
511 if (dac_or_dbi) { // DAC
512 flags = 1; // say its locked to get blank
513 deskew = settings[byte] & 0xff;
514 } else { // DBI
515 flags = settings[byte] & 7;
516 deskew = (settings[byte] >> 3) & 0x7f;
517 }
518 ddr_print(" %3d %c", deskew, fc[flags^1]);
519 }
520 ddr_print("\n");
521}
522
523// Evaluate the DAC settings array
524static int
525evaluate_DAC_settings(int ddr_interface_64b, int ecc_ena, int *settings)
526{
527 int byte, dac;
528 int last = (ddr_interface_64b) ? 7 : 3;
529
530 // this looks only for DAC values that are EVEN
531 for (byte = (last+ecc_ena); byte >= 0; --byte) {
532 dac = settings[byte] & 0xff;
533 if ((dac & 1) == 0)
534 return 1;
535 }
536 return 0;
537}
538
539static void
540Perform_Offset_Training(bdk_node_t node, int rank_mask, int ddr_interface_num)
541{
542 bdk_lmcx_phy_ctl_t lmc_phy_ctl;
543 uint64_t orig_phy_ctl;
544 const char *s;
545
546 /*
547 * 6.9.8 LMC Offset Training
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100548 *
David Hendricks2004b932018-03-09 13:58:27 -0800549 * LMC requires input-receiver offset training.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100550 *
David Hendricks2004b932018-03-09 13:58:27 -0800551 * 1. Write LMC(0)_PHY_CTL[DAC_ON] = 1
552 */
553 lmc_phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
554 orig_phy_ctl = lmc_phy_ctl.u;
555 lmc_phy_ctl.s.dac_on = 1;
556
557 // allow full CSR override
558 if ((s = lookup_env_parameter_ull("ddr_phy_ctl")) != NULL) {
559 lmc_phy_ctl.u = strtoull(s, NULL, 0);
560 }
561
562 // do not print or write if CSR does not change...
563 if (lmc_phy_ctl.u != orig_phy_ctl) {
David Hendricks7d48ac52018-03-09 14:30:38 -0800564 ddr_print("PHY_CTL : 0x%016llx\n", lmc_phy_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -0800565 DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), lmc_phy_ctl.u);
566 }
567
568#if 0
569 // FIXME? do we really need to show RODT here?
570 bdk_lmcx_comp_ctl2_t lmc_comp_ctl2;
571 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
572 ddr_print("Read ODT_CTL : 0x%x (%d ohms)\n",
573 lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
574#endif
575
576 /*
577 * 2. Write LMC(0)_SEQ_CTL[SEQ_SEL] = 0x0B and
578 * LMC(0)_SEQ_CTL[INIT_START] = 1.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100579 *
David Hendricks2004b932018-03-09 13:58:27 -0800580 * 3. Wait for LMC(0)_SEQ_CTL[SEQ_COMPLETE] to be set to 1.
581 */
582 perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x0B); /* Offset training sequence */
583
584}
585
586static void
587Perform_Internal_VREF_Training(bdk_node_t node, int rank_mask, int ddr_interface_num)
588{
589 bdk_lmcx_ext_config_t ext_config;
590
591 /*
592 * 6.9.9 LMC Internal Vref Training
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100593 *
David Hendricks2004b932018-03-09 13:58:27 -0800594 * LMC requires input-reference-voltage training.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100595 *
David Hendricks2004b932018-03-09 13:58:27 -0800596 * 1. Write LMC(0)_EXT_CONFIG[VREFINT_SEQ_DESKEW] = 0.
597 */
598 ext_config.u = BDK_CSR_READ(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num));
599 ext_config.s.vrefint_seq_deskew = 0;
600
601 VB_PRT(VBL_SEQ, "N%d.LMC%d: Performing LMC sequence: vrefint_seq_deskew = %d\n",
602 node, ddr_interface_num, ext_config.s.vrefint_seq_deskew);
603
604 DRAM_CSR_WRITE(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num), ext_config.u);
605
606 /*
607 * 2. Write LMC(0)_SEQ_CTL[SEQ_SEL] = 0x0a and
608 * LMC(0)_SEQ_CTL[INIT_START] = 1.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100609 *
David Hendricks2004b932018-03-09 13:58:27 -0800610 * 3. Wait for LMC(0)_SEQ_CTL[SEQ_COMPLETE] to be set to 1.
611 */
612 perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x0A); /* LMC Internal Vref Training */
613}
614
615#define dbg_avg(format, ...) VB_PRT(VBL_DEV, format, ##__VA_ARGS__)
616static int
617process_samples_average(int16_t *bytes, int num_samples, int lmc, int lane_no)
618{
619 int i, savg, sadj, sum = 0, rng, ret, asum, trunc;
620 int16_t smin = 32767, smax = -32768;
621
622 dbg_avg("DBG_AVG%d.%d: ", lmc, lane_no);
623
624 for (i = 0; i < num_samples; i++) {
625 sum += bytes[i];
626 if (bytes[i] < smin) smin = bytes[i];
627 if (bytes[i] > smax) smax = bytes[i];
628 dbg_avg(" %3d", bytes[i]);
629 }
630 rng = smax - smin + 1;
631
632 dbg_avg(" (%3d, %3d, %2d)", smin, smax, rng);
633
634 asum = sum - smin - smax;
635
636 savg = divide_nint(sum * 10, num_samples);
637
638 sadj = divide_nint(asum * 10, (num_samples - 2));
639
640 trunc = asum / (num_samples - 2);
641
642 dbg_avg(" [%3d.%d, %3d.%d, %3d]", savg/10, savg%10, sadj/10, sadj%10, trunc);
643
644 sadj = divide_nint(sadj, 10);
645 if (trunc & 1)
646 ret = trunc;
647 else if (sadj & 1)
648 ret = sadj;
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100649 else
David Hendricks2004b932018-03-09 13:58:27 -0800650 ret = trunc + 1;
651
652 dbg_avg(" -> %3d\n", ret);
653
654 return ret;
655}
656
657
658#define DEFAULT_SAT_RETRY_LIMIT 11 // 1 + 10 retries
659static int default_lock_retry_limit = 20; // 20 retries // FIXME: make a var for overriding
660
661static int
662Perform_Read_Deskew_Training(bdk_node_t node, int rank_mask, int ddr_interface_num,
663 int spd_rawcard_AorB, int print_flags, int ddr_interface_64b)
664{
665 int unsaturated, locked;
666 //int nibble_sat;
667 int sat_retries, lock_retries, lock_retries_total, lock_retries_limit;
668 int print_first;
669 int print_them_all;
670 deskew_counts_t dsk_counts;
671 uint64_t saved_wr_deskew_ena;
672#if DESKEW_RODT_CTL
673 bdk_lmcx_comp_ctl2_t comp_ctl2;
674 int save_deskew_rodt_ctl = -1;
675#endif
676 int is_t88p2 = !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X); // added 81xx and 83xx
677
678 VB_PRT(VBL_FAE, "N%d.LMC%d: Performing Read Deskew Training.\n", node, ddr_interface_num);
679
680 // save original WR_DESKEW_ENA setting, and disable it for read deskew
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100681 saved_wr_deskew_ena = change_wr_deskew_ena(node, ddr_interface_num, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800682
683 sat_retries = 0;
684 lock_retries_total = 0;
685 unsaturated = 0;
686 print_first = VBL_FAE; // print the first one, FAE and above
687 print_them_all = dram_is_verbose(VBL_DEV4); // set to true for printing all normal deskew attempts
688
689 int loops, normal_loops = 1; // default to 1 NORMAL deskew training op...
690 const char *s;
691 if ((s = getenv("ddr_deskew_normal_loops")) != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -0800692 normal_loops = strtoul(s, NULL, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800693 }
694
695#if LOOK_FOR_STUCK_BYTE
696 // provide override for STUCK BYTE RESETS
697 int do_stuck_reset = ENABLE_STUCK_BYTE_RESET;
698 if ((s = getenv("ddr_enable_stuck_byte_reset")) != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -0800699 do_stuck_reset = !!strtoul(s, NULL, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800700 }
701#endif
702
703#if DESKEW_RODT_CTL
704 if ((s = getenv("ddr_deskew_rodt_ctl")) != NULL) {
705 int deskew_rodt_ctl = strtoul(s, NULL, 0);
706 comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
707 save_deskew_rodt_ctl = comp_ctl2.s.rodt_ctl;
708 comp_ctl2.s.rodt_ctl = deskew_rodt_ctl;
709 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), comp_ctl2.u);
710 }
711#endif
712
713 lock_retries_limit = default_lock_retry_limit;
714 if (! CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) // added 81xx and 83xx
715 lock_retries_limit *= 2; // give pass 2.0 twice as many
716
717 do { /* while (sat_retries < sat_retry_limit) */
718
719 /*
720 * 6.9.10 LMC Deskew Training
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100721 *
David Hendricks2004b932018-03-09 13:58:27 -0800722 * LMC requires input-read-data deskew training.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100723 *
David Hendricks2004b932018-03-09 13:58:27 -0800724 * 1. Write LMC(0)_EXT_CONFIG[VREFINT_SEQ_DESKEW] = 1.
725 */
David Hendricks7d48ac52018-03-09 14:30:38 -0800726 VB_PRT(VBL_SEQ, "N%d.LMC%d: Performing LMC sequence: Set vrefint_seq_deskew = 1\n",
David Hendricks2004b932018-03-09 13:58:27 -0800727 node, ddr_interface_num);
728 DRAM_CSR_MODIFY(ext_config, node, BDK_LMCX_EXT_CONFIG(ddr_interface_num),
David Hendricks7d48ac52018-03-09 14:30:38 -0800729 ext_config.s.vrefint_seq_deskew = 1); /* Set Deskew sequence */
David Hendricks2004b932018-03-09 13:58:27 -0800730
731 /*
732 * 2. Write LMC(0)_SEQ_CTL[SEQ_SEL] = 0x0A and
733 * LMC(0)_SEQ_CTL[INIT_START] = 1.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100734 *
David Hendricks2004b932018-03-09 13:58:27 -0800735 * 3. Wait for LMC(0)_SEQ_CTL[SEQ_COMPLETE] to be set to 1.
736 */
737 DRAM_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
David Hendricks7d48ac52018-03-09 14:30:38 -0800738 phy_ctl.s.phy_dsk_reset = 1); /* RESET Deskew sequence */
David Hendricks2004b932018-03-09 13:58:27 -0800739 perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x0A); /* LMC Deskew Training */
740
David Hendricks7d48ac52018-03-09 14:30:38 -0800741 lock_retries = 0;
David Hendricks2004b932018-03-09 13:58:27 -0800742
743 perform_read_deskew_training:
744 // maybe perform the NORMAL deskew training sequence multiple times before looking at lock status
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100745 for (loops = 0; loops < normal_loops; loops++) {
David Hendricks2004b932018-03-09 13:58:27 -0800746 DRAM_CSR_MODIFY(phy_ctl, node, BDK_LMCX_PHY_CTL(ddr_interface_num),
747 phy_ctl.s.phy_dsk_reset = 0); /* Normal Deskew sequence */
748 perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x0A); /* LMC Deskew Training */
749 }
750 // Moved this from Validate_Read_Deskew_Training
751 /* Allow deskew results to stabilize before evaluating them. */
752 bdk_wait_usec(deskew_validation_delay);
753
754 // Now go look at lock and saturation status...
755 Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, print_first);
David Hendricks7d48ac52018-03-09 14:30:38 -0800756 if (print_first && !print_them_all) // after printing the first and not doing them all, no more
757 print_first = 0;
David Hendricks2004b932018-03-09 13:58:27 -0800758
759 unsaturated = (dsk_counts.saturated == 0);
David Hendricks7d48ac52018-03-09 14:30:38 -0800760 locked = (dsk_counts.unlocked == 0);
David Hendricks2004b932018-03-09 13:58:27 -0800761 //nibble_sat = (dsk_counts.nibsat_errs != 0);
762
David Hendricks7d48ac52018-03-09 14:30:38 -0800763 // only do locking retries if unsaturated or rawcard A or B, otherwise full SAT retry
764 if (unsaturated || (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/)) {
765 if (!locked) { // and not locked
766 lock_retries++;
767 lock_retries_total++;
768 if (lock_retries <= lock_retries_limit) {
769 goto perform_read_deskew_training;
770 } else {
771 VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES failed after %d retries\n",
David Hendricks2004b932018-03-09 13:58:27 -0800772 node, ddr_interface_num, lock_retries_limit);
David Hendricks7d48ac52018-03-09 14:30:38 -0800773 }
774 } else {
775 if (lock_retries_total > 0) // only print if we did try
776 VB_PRT(VBL_TME, "N%d.LMC%d: LOCK RETRIES successful after %d retries\n",
David Hendricks2004b932018-03-09 13:58:27 -0800777 node, ddr_interface_num, lock_retries);
David Hendricks7d48ac52018-03-09 14:30:38 -0800778 }
779 } /* if (unsaturated || spd_rawcard_AorB) */
David Hendricks2004b932018-03-09 13:58:27 -0800780
781 ++sat_retries;
782
783#if LOOK_FOR_STUCK_BYTE
784 // FIXME: this is a bit of a hack at the moment...
785 // We want to force a Deskew RESET hopefully to unstick the bytes values
786 // and then resume normal deskew training as usual.
787 // For now, do only if it is all locked...
788 if (locked && (dsk_counts.bytes_stuck != 0)) {
789 BDK_CSR_INIT(lmc_config, node, BDK_LMCX_CONFIG(ddr_interface_num));
790 if (do_stuck_reset && lmc_config.s.mode_x4dev) { // FIXME: only when x4!!
791 unsaturated = 0; // to always make sure the while continues
792 VB_PRT(VBL_TME, "N%d.LMC%d: STUCK BYTE (0x%x), forcing deskew RESET\n",
793 node, ddr_interface_num, dsk_counts.bytes_stuck);
794 continue; // bypass the rest to get back to the RESET
795 } else {
796 VB_PRT(VBL_TME, "N%d.LMC%d: STUCK BYTE (0x%x), ignoring deskew RESET\n",
797 node, ddr_interface_num, dsk_counts.bytes_stuck);
798 }
799 }
800#endif
David Hendricks7d48ac52018-03-09 14:30:38 -0800801 /*
802 * At this point, check for a DDR4 RDIMM that will not benefit from SAT retries; if so, no retries
803 */
804 if (spd_rawcard_AorB && !is_t88p2 /*&& !nibble_sat*/) {
805 VB_PRT(VBL_TME, "N%d.LMC%d: Read Deskew Training Loop: Exiting for RAWCARD == A or B.\n",
David Hendricks2004b932018-03-09 13:58:27 -0800806 node, ddr_interface_num);
David Hendricks7d48ac52018-03-09 14:30:38 -0800807 break; // no sat or lock retries
808 }
David Hendricks2004b932018-03-09 13:58:27 -0800809
810 } while (!unsaturated && (sat_retries < DEFAULT_SAT_RETRY_LIMIT));
811
812#if DESKEW_RODT_CTL
813 if (save_deskew_rodt_ctl != -1) {
814 comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
815 comp_ctl2.s.rodt_ctl = save_deskew_rodt_ctl;
816 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), comp_ctl2.u);
817 }
818#endif
819
820 VB_PRT(VBL_FAE, "N%d.LMC%d: Read Deskew Training %s. %d sat-retries, %d lock-retries\n",
821 node, ddr_interface_num,
822 (sat_retries >= DEFAULT_SAT_RETRY_LIMIT) ? "Timed Out" : "Completed",
823 sat_retries-1, lock_retries_total);
824
825 // restore original WR_DESKEW_ENA setting
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100826 change_wr_deskew_ena(node, ddr_interface_num, saved_wr_deskew_ena);
David Hendricks2004b932018-03-09 13:58:27 -0800827
828 if ((dsk_counts.nibrng_errs != 0) || (dsk_counts.nibunl_errs != 0)) {
David Hendricks7d48ac52018-03-09 14:30:38 -0800829 debug_print("N%d.LMC%d: NIBBLE ERROR(S) found, returning FAULT\n",
830 node, ddr_interface_num);
831 return -1; // we did retry locally, they did not help
David Hendricks2004b932018-03-09 13:58:27 -0800832 }
833
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100834 // NOTE: we (currently) always print one last training validation before starting Read Leveling...
David Hendricks2004b932018-03-09 13:58:27 -0800835
836 return 0;
837}
838
839static void
840do_write_deskew_op(bdk_node_t node, int ddr_interface_num,
841 int bit_sel, int byte_sel, int ena)
842{
843 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
844
845 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
846 SET_DDR_DLL_CTL3(bit_select, bit_sel);
847 SET_DDR_DLL_CTL3(byte_sel, byte_sel);
848 SET_DDR_DLL_CTL3(wr_deskew_ena, ena);
David Hendricks7d48ac52018-03-09 14:30:38 -0800849 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -0800850
851 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
852}
853
854static void
855set_write_deskew_offset(bdk_node_t node, int ddr_interface_num,
856 int bit_sel, int byte_sel, int offset)
857{
858 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
859
860 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
861 SET_DDR_DLL_CTL3(bit_select, bit_sel);
862 SET_DDR_DLL_CTL3(byte_sel, byte_sel);
863 SET_DDR_DLL_CTL3(offset, offset);
David Hendricks7d48ac52018-03-09 14:30:38 -0800864 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -0800865
866 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
867 SET_DDR_DLL_CTL3(wr_deskew_ld, 1);
David Hendricks7d48ac52018-03-09 14:30:38 -0800868 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -0800869
870 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
871}
872
873static void
874Update_Write_Deskew_Settings(bdk_node_t node, int ddr_interface_num, deskew_data_t *dskdat)
875{
876 bdk_lmcx_config_t lmc_config;
877 int bit_num;
878 int byte_lane, byte_limit;
879
880 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
881 byte_limit = ((lmc_config.s.mode32b) ? 4 : 8) + lmc_config.s.ecc_ena;
882
883 for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) {
David Hendricks7d48ac52018-03-09 14:30:38 -0800884 for (bit_num = 0; bit_num <= 7; ++bit_num) {
David Hendricks2004b932018-03-09 13:58:27 -0800885
886 set_write_deskew_offset(node, ddr_interface_num, bit_num, byte_lane + 1,
887 dskdat->bytes[byte_lane].bits[bit_num]);
888
889 } /* for (bit_num = 0; bit_num <= 7; ++bit_num) */
890 } /* for (byte_lane = 0; byte_lane < byte_limit; byte_lane++) */
David Hendricks7d48ac52018-03-09 14:30:38 -0800891
David Hendricks2004b932018-03-09 13:58:27 -0800892 return;
893}
894
895#define ALL_BYTES 0x0A
896#define BS_NOOP 0x09
897#define BS_RESET 0x0F
898#define BS_REUSE 0x0A
899
900// set all entries to the same value (used during training)
901static void
902Set_Write_Deskew_Settings(bdk_node_t node, int ddr_interface_num, int value)
903{
904 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
905 int bit_num;
906
907 VB_PRT(VBL_DEV2, "N%d.LMC%d: SetWriteDeskew: WRITE %d\n", node, ddr_interface_num, value);
908
909 for (bit_num = 0; bit_num <= 7; ++bit_num) {
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100910
David Hendricks2004b932018-03-09 13:58:27 -0800911 // write a bit-deskew value to all bit-lanes of all bytes
912 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
913 SET_DDR_DLL_CTL3(bit_select, bit_num);
914 SET_DDR_DLL_CTL3(byte_sel, ALL_BYTES); // FIXME? will this work in 32-bit mode?
915 SET_DDR_DLL_CTL3(offset, value);
916 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
917
918 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
919 SET_DDR_DLL_CTL3(wr_deskew_ld, 1);
920 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
921
922 } /* for (bit_num = 0; bit_num <= 7; ++bit_num) */
923
924#if 0
925 // FIXME: for debug use only
926 Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
927 Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
928#endif
929
930 return;
931}
932
933typedef struct {
934 uint8_t count[8];
935 uint8_t start[8];
936 uint8_t best_count[8];
937 uint8_t best_start[8];
938} deskew_bytelane_t;
939typedef struct {
940 deskew_bytelane_t bytes[9];
941} deskew_rank_t;
942
943deskew_rank_t deskew_history[4];
944
945#define DSKVAL_INCR 4
946
947static void
948Neutral_Write_Deskew_Setup(bdk_node_t node, int ddr_interface_num)
949{
950 // first: NO-OP, Select all bytes, Disable write bit-deskew
951 ddr_print("N%d.LMC%d: NEUTRAL Write Deskew Setup: first: NOOP\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100952 do_write_deskew_op(node, ddr_interface_num, BS_NOOP, ALL_BYTES, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800953 //Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
954 //Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
955
956 // enable write bit-deskew and RESET the settings
957 ddr_print("N%d.LMC%d: NEUTRAL Write Deskew Setup: wr_ena: RESET\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100958 do_write_deskew_op(node, ddr_interface_num, BS_RESET, ALL_BYTES, 1);
David Hendricks2004b932018-03-09 13:58:27 -0800959 //Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
960 //Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
961}
962
963static void
964Perform_Write_Deskew_Training(bdk_node_t node, int ddr_interface_num)
965{
966 deskew_data_t dskdat;
967 int byte, bit_num;
968 int dskval, rankx, rank_mask, active_ranks, errors, bit_errs;
969 uint64_t hw_rank_offset;
970 uint64_t bad_bits[2];
971 uint64_t phys_addr;
972 deskew_rank_t *dhp;
973 int num_lmcs = __bdk_dram_get_num_lmc(node);
974
975 BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(ddr_interface_num));
976 rank_mask = lmcx_config.s.init_status; // FIXME: is this right when we run?
977
978 // this should be correct for 1 or 2 ranks, 1 or 2 DIMMs
979 hw_rank_offset = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena + (num_lmcs/2));
980
981 VB_PRT(VBL_FAE, "N%d.LMC%d: Performing Write Deskew Training.\n", node, ddr_interface_num);
982
983 // first: NO-OP, Select all bytes, Disable write bit-deskew
984 ddr_print("N%d.LMC%d: WriteDeskewConfig: first: NOOP\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100985 do_write_deskew_op(node, ddr_interface_num, BS_NOOP, ALL_BYTES, 0);
David Hendricks2004b932018-03-09 13:58:27 -0800986 //Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
987 //Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
988
989 // enable write bit-deskew and RESET the settings
990 ddr_print("N%d.LMC%d: WriteDeskewConfig: wr_ena: RESET\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100991 do_write_deskew_op(node, ddr_interface_num, BS_RESET, ALL_BYTES, 1);
David Hendricks2004b932018-03-09 13:58:27 -0800992 //Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
993 //Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
994
995#if 0
996 // enable write bit-deskew and REUSE read bit-deskew settings
997 ddr_print("N%d.LMC%d: WriteDeskewConfig: wr_ena: REUSE\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +0100998 do_write_deskew_op(node, ddr_interface_num, BS_REUSE, ALL_BYTES, 1);
David Hendricks2004b932018-03-09 13:58:27 -0800999 Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
1000 Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
1001#endif
1002
1003#if 1
1004 memset(deskew_history, 0, sizeof(deskew_history));
1005
1006 for (dskval = 0; dskval < 128; dskval += DSKVAL_INCR) {
1007
1008 Set_Write_Deskew_Settings(node, ddr_interface_num, dskval);
1009
1010 active_ranks = 0;
1011 for (rankx = 0; rankx < 4; rankx++) {
1012 if (!(rank_mask & (1 << rankx)))
1013 continue;
1014 dhp = &deskew_history[rankx];
1015 phys_addr = hw_rank_offset * active_ranks;
1016 active_ranks++;
1017
1018 errors = test_dram_byte_hw(node, ddr_interface_num, phys_addr, 0, bad_bits);
1019
1020 for (byte = 0; byte <= 8; byte++) { // do bytelane(s)
1021
1022 // check errors
1023 if (errors & (1 << byte)) { // yes, error(s) in the byte lane in this rank
1024 bit_errs = ((byte == 8) ? bad_bits[1] : bad_bits[0] >> (8 * byte)) & 0xFFULL;
1025
David Hendricks7d48ac52018-03-09 14:30:38 -08001026 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Value %d: Address 0x%012llx errors 0x%x/0x%x\n",
David Hendricks2004b932018-03-09 13:58:27 -08001027 node, ddr_interface_num, rankx, byte,
1028 dskval, phys_addr, errors, bit_errs);
1029
1030 for (bit_num = 0; bit_num <= 7; bit_num++) {
1031 if (!(bit_errs & (1 << bit_num)))
1032 continue;
1033 if (dhp->bytes[byte].count[bit_num] > 0) { // had started run
1034 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Bit %d Value %d: stopping a run here\n",
1035 node, ddr_interface_num, rankx, byte, bit_num, dskval);
1036 dhp->bytes[byte].count[bit_num] = 0; // stop now
1037 }
1038 } /* for (bit_num = 0; bit_num <= 7; bit_num++) */
1039
1040 // FIXME: else had not started run - nothing else to do?
1041 } else { // no error in the byte lane
1042 for (bit_num = 0; bit_num <= 7; bit_num++) {
1043 if (dhp->bytes[byte].count[bit_num] == 0) { // first success, set run start
1044 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Bit %d Value %d: starting a run here\n",
1045 node, ddr_interface_num, rankx, byte, bit_num, dskval);
1046 dhp->bytes[byte].start[bit_num] = dskval;
1047 }
1048 dhp->bytes[byte].count[bit_num] += DSKVAL_INCR; // bump run length
1049
1050 // is this now the biggest window?
1051 if (dhp->bytes[byte].count[bit_num] > dhp->bytes[byte].best_count[bit_num]) {
1052 dhp->bytes[byte].best_count[bit_num] = dhp->bytes[byte].count[bit_num];
1053 dhp->bytes[byte].best_start[bit_num] = dhp->bytes[byte].start[bit_num];
1054 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: Byte %d Bit %d Value %d: updating best to %d/%d\n",
1055 node, ddr_interface_num, rankx, byte, bit_num, dskval,
1056 dhp->bytes[byte].best_start[bit_num],
1057 dhp->bytes[byte].best_count[bit_num]);
1058 }
1059 } /* for (bit_num = 0; bit_num <= 7; bit_num++) */
1060 } /* error in the byte lane */
1061 } /* for (byte = 0; byte <= 8; byte++) */
1062 } /* for (rankx = 0; rankx < 4; rankx++) */
1063 } /* for (dskval = 0; dskval < 128; dskval++) */
1064
1065
1066 for (byte = 0; byte <= 8; byte++) { // do bytelane(s)
1067
1068 for (bit_num = 0; bit_num <= 7; bit_num++) { // do bits
1069 int bit_beg, bit_end;
1070
1071 bit_beg = 0;
1072 bit_end = 128;
1073
1074 for (rankx = 0; rankx < 4; rankx++) { // merge ranks
1075 int rank_beg, rank_end, rank_count;
1076 if (!(rank_mask & (1 << rankx)))
1077 continue;
1078
1079 dhp = &deskew_history[rankx];
1080 rank_beg = dhp->bytes[byte].best_start[bit_num];
1081 rank_count = dhp->bytes[byte].best_count[bit_num];
1082
1083 if (!rank_count) {
1084 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: Byte %d Bit %d: EMPTY\n",
1085 node, ddr_interface_num, rankx, byte, bit_num);
1086 continue;
1087 }
1088
1089 bit_beg = max(bit_beg, rank_beg);
1090 rank_end = rank_beg + rank_count - DSKVAL_INCR;
1091 bit_end = min(bit_end, rank_end);
1092
1093 } /* for (rankx = 0; rankx < 4; rankx++) */
1094
1095 dskdat.bytes[byte].bits[bit_num] = (bit_end + bit_beg) / 2;
1096
1097 } /* for (bit_num = 0; bit_num <= 7; bit_num++) */
1098 } /* for (byte = 0; byte <= 8; byte++) */
1099
1100#endif
1101
1102 // update the write bit-deskew settings with final settings
1103 ddr_print("N%d.LMC%d: WriteDeskewConfig: wr_ena: UPDATE\n", node, ddr_interface_num);
1104 Update_Write_Deskew_Settings(node, ddr_interface_num, &dskdat);
1105 Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
1106 Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
1107
1108 // last: NO-OP, Select all bytes, MUST leave write bit-deskew enabled
1109 ddr_print("N%d.LMC%d: WriteDeskewConfig: last: wr_ena: NOOP\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001110 do_write_deskew_op(node, ddr_interface_num, BS_NOOP, ALL_BYTES, 1);
David Hendricks2004b932018-03-09 13:58:27 -08001111 //Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
1112 //Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
1113
1114#if 0
1115 // FIXME: disable/delete this when write bit-deskew works...
1116 // final: NO-OP, Select all bytes, do NOT leave write bit-deskew enabled
1117 ddr_print("N%d.LMC%d: WriteDeskewConfig: final: read: NOOP\n", node, ddr_interface_num);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001118 do_write_deskew_op(node, ddr_interface_num, BS_NOOP, ALL_BYTES, 0);
David Hendricks2004b932018-03-09 13:58:27 -08001119 Get_Deskew_Settings(node, ddr_interface_num, &dskdat);
1120 Display_Deskew_Data(node, ddr_interface_num, &dskdat, VBL_NORM);
1121#endif
1122}
1123
1124#define SCALING_FACTOR (1000)
1125#define Dprintf debug_print // make this "ddr_print" for extra debug output below
1126static int compute_Vref_1slot_2rank(int rtt_wr, int rtt_park, int dqx_ctl, int rank_count)
1127{
1128 uint64_t Reff_s;
1129 uint64_t Rser_s = 15;
1130 uint64_t Vdd = 1200;
1131 uint64_t Vref;
1132 //uint64_t Vl;
1133 uint64_t rtt_wr_s = (((rtt_wr == 0) || (rtt_wr == 99)) ? 1*1024*1024 : rtt_wr); // 99 == HiZ
1134 uint64_t rtt_park_s = (((rtt_park == 0) || ((rank_count == 1) && (rtt_wr != 0))) ? 1*1024*1024 : rtt_park);
1135 uint64_t dqx_ctl_s = (dqx_ctl == 0 ? 1*1024*1024 : dqx_ctl);
1136 int Vref_value;
1137 uint64_t Rangepc = 6000; // range1 base is 60%
1138 uint64_t Vrefpc;
1139 int Vref_range = 0;
1140
1141 Dprintf("rtt_wr = %d, rtt_park = %d, dqx_ctl = %d\n", rtt_wr, rtt_park, dqx_ctl);
1142 Dprintf("rtt_wr_s = %d, rtt_park_s = %d, dqx_ctl_s = %d\n", rtt_wr_s, rtt_park_s, dqx_ctl_s);
1143
1144 Reff_s = divide_nint((rtt_wr_s * rtt_park_s) , (rtt_wr_s + rtt_park_s));
1145 Dprintf("Reff_s = %d\n", Reff_s);
1146
1147 //Vl = (((Rser_s + dqx_ctl_s) * SCALING_FACTOR) / (Rser_s + dqx_ctl_s + Reff_s)) * Vdd / SCALING_FACTOR;
1148 //printf("Vl = %d\n", Vl);
1149
1150 Vref = (((Rser_s + dqx_ctl_s) * SCALING_FACTOR) / (Rser_s + dqx_ctl_s + Reff_s)) + SCALING_FACTOR;
1151 Dprintf("Vref = %d\n", Vref);
1152
1153 Vref = (Vref * Vdd) / 2 / SCALING_FACTOR;
1154 Dprintf("Vref = %d\n", Vref);
1155
1156 Vrefpc = (Vref * 100 * 100) / Vdd;
1157 Dprintf("Vrefpc = %d\n", Vrefpc);
1158
1159 if (Vrefpc < Rangepc) { // < range1 base, use range2
David Hendricks7d48ac52018-03-09 14:30:38 -08001160 Vref_range = 1 << 6; // set bit A6 for range2
1161 Rangepc = 4500; // range2 base is 45%
David Hendricks2004b932018-03-09 13:58:27 -08001162 }
1163
1164 Vref_value = divide_nint(Vrefpc - Rangepc, 65);
1165 if (Vref_value < 0)
David Hendricks7d48ac52018-03-09 14:30:38 -08001166 Vref_value = Vref_range; // set to base of range as lowest value
David Hendricks2004b932018-03-09 13:58:27 -08001167 else
David Hendricks7d48ac52018-03-09 14:30:38 -08001168 Vref_value |= Vref_range;
David Hendricks2004b932018-03-09 13:58:27 -08001169 Dprintf("Vref_value = %d (0x%02x)\n", Vref_value, Vref_value);
1170
1171 debug_print("rtt_wr:%d, rtt_park:%d, dqx_ctl:%d, Vref_value:%d (0x%x)\n",
1172 rtt_wr, rtt_park, dqx_ctl, Vref_value, Vref_value);
1173
1174 return Vref_value;
1175}
1176static int compute_Vref_2slot_2rank(int rtt_wr, int rtt_park_00, int rtt_park_01, int dqx_ctl, int rtt_nom)
1177{
1178 //uint64_t Rser = 15;
1179 uint64_t Vdd = 1200;
1180 //uint64_t Vref;
1181 uint64_t Vl, Vlp, Vcm;
1182 uint64_t Rd0, Rd1, Rpullup;
1183 uint64_t rtt_wr_s = (((rtt_wr == 0) || (rtt_wr == 99)) ? 1*1024*1024 : rtt_wr); // 99 == HiZ
1184 uint64_t rtt_park_00_s = (rtt_park_00 == 0 ? 1*1024*1024 : rtt_park_00);
1185 uint64_t rtt_park_01_s = (rtt_park_01 == 0 ? 1*1024*1024 : rtt_park_01);
1186 uint64_t dqx_ctl_s = (dqx_ctl == 0 ? 1*1024*1024 : dqx_ctl);
1187 uint64_t rtt_nom_s = (rtt_nom == 0 ? 1*1024*1024 : rtt_nom);
1188 int Vref_value;
1189 uint64_t Rangepc = 6000; // range1 base is 60%
1190 uint64_t Vrefpc;
1191 int Vref_range = 0;
1192
1193 // Rd0 = (RTT_NOM /*parallel*/ RTT_WR) + 15 = ((RTT_NOM * RTT_WR) / (RTT_NOM + RTT_WR)) + 15
1194 Rd0 = divide_nint((rtt_nom_s * rtt_wr_s), (rtt_nom_s + rtt_wr_s)) + 15;
1195 //printf("Rd0 = %ld\n", Rd0);
1196
1197 // Rd1 = (RTT_PARK_00 /*parallel*/ RTT_PARK_01) + 15 = ((RTT_PARK_00 * RTT_PARK_01) / (RTT_PARK_00 + RTT_PARK_01)) + 15
1198 Rd1 = divide_nint((rtt_park_00_s * rtt_park_01_s), (rtt_park_00_s + rtt_park_01_s)) + 15;
1199 //printf("Rd1 = %ld\n", Rd1);
1200
1201 // Rpullup = Rd0 /*parallel*/ Rd1 = (Rd0 * Rd1) / (Rd0 + Rd1)
1202 Rpullup = divide_nint((Rd0 * Rd1), (Rd0 + Rd1));
1203 //printf("Rpullup = %ld\n", Rpullup);
1204
1205 // Vl = (DQX_CTL / (DQX_CTL + Rpullup)) * 1.2
1206 Vl = divide_nint((dqx_ctl_s * Vdd), (dqx_ctl_s + Rpullup));
1207 //printf("Vl = %ld\n", Vl);
1208
1209 // Vlp = ((15 / Rd0) * (1.2 - Vl)) + Vl
1210 Vlp = divide_nint((15 * (Vdd - Vl)), Rd0) + Vl;
1211 //printf("Vlp = %ld\n", Vlp);
1212
1213 // Vcm = (Vlp + 1.2) / 2
1214 Vcm = divide_nint((Vlp + Vdd), 2);
1215 //printf("Vcm = %ld\n", Vcm);
1216
1217 // Vrefpc = (Vcm / 1.2) * 100
1218 Vrefpc = divide_nint((Vcm * 100 * 100), Vdd);
1219 //printf("Vrefpc = %ld\n", Vrefpc);
1220
1221 if (Vrefpc < Rangepc) { // < range1 base, use range2
David Hendricks7d48ac52018-03-09 14:30:38 -08001222 Vref_range = 1 << 6; // set bit A6 for range2
1223 Rangepc = 4500; // range2 base is 45%
David Hendricks2004b932018-03-09 13:58:27 -08001224 }
1225
1226 Vref_value = divide_nint(Vrefpc - Rangepc, 65);
1227 if (Vref_value < 0)
David Hendricks7d48ac52018-03-09 14:30:38 -08001228 Vref_value = Vref_range; // set to base of range as lowest value
David Hendricks2004b932018-03-09 13:58:27 -08001229 else
David Hendricks7d48ac52018-03-09 14:30:38 -08001230 Vref_value |= Vref_range;
David Hendricks2004b932018-03-09 13:58:27 -08001231 //printf("Vref_value = %d (0x%02x)\n", Vref_value, Vref_value);
1232
1233 debug_print("rtt_wr:%d, rtt_park_00:%d, rtt_park_01:%d, dqx_ctl:%d, rtt_nom:%d, Vref_value:%d (0x%x)\n",
David Hendricks7d48ac52018-03-09 14:30:38 -08001234 rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom, Vref_value, Vref_value);
David Hendricks2004b932018-03-09 13:58:27 -08001235
1236 return Vref_value;
1237}
1238
1239// NOTE: only call this for DIMMs with 1 or 2 ranks, not 4.
1240int
1241compute_vref_value(bdk_node_t node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -08001242 int rankx, int dimm_count, int rank_count,
1243 impedence_values_t *imp_values, int is_stacked_die)
David Hendricks2004b932018-03-09 13:58:27 -08001244{
1245 int computed_final_vref_value = 0;
1246
1247 /* Calculate an override of the measured Vref value
1248 but only for configurations we know how to...*/
1249 // we have code for 2-rank DIMMs in both 1-slot or 2-slot configs,
1250 // and can use the 2-rank 1-slot code for 1-rank DIMMs in 1-slot configs
1251 // and can use the 2-rank 2-slot code for 1-rank DIMMs in 2-slot configs
1252
1253 int rtt_wr, dqx_ctl, rtt_nom, index;
1254 bdk_lmcx_modereg_params1_t lmc_modereg_params1;
1255 bdk_lmcx_modereg_params2_t lmc_modereg_params2;
1256 bdk_lmcx_comp_ctl2_t comp_ctl2;
1257
1258 lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
1259 lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
1260 comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
1261 dqx_ctl = imp_values->dqx_strength[comp_ctl2.s.dqx_ctl];
1262
1263 // WR always comes from the current rank
1264 index = (lmc_modereg_params1.u >> (rankx * 12 + 5)) & 0x03;
1265 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) {
1266 index |= lmc_modereg_params1.u >> (51+rankx-2) & 0x04;
1267 }
1268 rtt_wr = imp_values->rtt_wr_ohms [index];
1269
1270 // separate calculations for 1 vs 2 DIMMs per LMC
1271 if (dimm_count == 1) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001272 // PARK comes from this rank if 1-rank, otherwise other rank
1273 index = (lmc_modereg_params2.u >> ((rankx ^ (rank_count - 1)) * 10 + 0)) & 0x07;
1274 int rtt_park = imp_values->rtt_nom_ohms[index];
1275 computed_final_vref_value = compute_Vref_1slot_2rank(rtt_wr, rtt_park, dqx_ctl, rank_count);
David Hendricks2004b932018-03-09 13:58:27 -08001276 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001277 // get both PARK values from the other DIMM
1278 index = (lmc_modereg_params2.u >> ((rankx ^ 0x02) * 10 + 0)) & 0x07;
1279 int rtt_park_00 = imp_values->rtt_nom_ohms[index];
1280 index = (lmc_modereg_params2.u >> ((rankx ^ 0x03) * 10 + 0)) & 0x07;
1281 int rtt_park_01 = imp_values->rtt_nom_ohms[index];
1282 // NOM comes from this rank if 1-rank, otherwise other rank
1283 index = (lmc_modereg_params1.u >> ((rankx ^ (rank_count - 1)) * 12 + 9)) & 0x07;
1284 rtt_nom = imp_values->rtt_nom_ohms[index];
1285 computed_final_vref_value = compute_Vref_2slot_2rank(rtt_wr, rtt_park_00, rtt_park_01, dqx_ctl, rtt_nom);
David Hendricks2004b932018-03-09 13:58:27 -08001286 }
1287
1288#if ENABLE_COMPUTED_VREF_ADJUSTMENT
1289 {
1290 int saved_final_vref_value = computed_final_vref_value;
David Hendricks7d48ac52018-03-09 14:30:38 -08001291 BDK_CSR_INIT(lmc_config, node, BDK_LMCX_CONFIG(ddr_interface_num));
1292 /*
1293 New computed Vref = existing computed Vref – X
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001294
David Hendricks7d48ac52018-03-09 14:30:38 -08001295 The value of X is depending on different conditions. Both #122 and #139 are 2Rx4 RDIMM,
1296 while #124 is stacked die 2Rx4, so I conclude the results into two conditions:
David Hendricks2004b932018-03-09 13:58:27 -08001297
David Hendricks7d48ac52018-03-09 14:30:38 -08001298 1. Stacked Die: 2Rx4
1299 1-slot: offset = 7. i, e New computed Vref = existing computed Vref – 7
1300 2-slot: offset = 6
David Hendricks2004b932018-03-09 13:58:27 -08001301
1302 2. Regular: 2Rx4
1303 1-slot: offset = 3
David Hendricks7d48ac52018-03-09 14:30:38 -08001304 2-slot: offset = 2
1305 */
1306 // we know we never get called unless DDR4, so test just the other conditions
1307 if((!!__bdk_dram_is_rdimm(node, 0)) &&
1308 (rank_count == 2) &&
1309 (lmc_config.s.mode_x4dev))
1310 { // it must first be RDIMM and 2-rank and x4
1311 if (is_stacked_die) { // now do according to stacked die or not...
1312 computed_final_vref_value -= (dimm_count == 1) ? 7 : 6;
1313 } else {
1314 computed_final_vref_value -= (dimm_count == 1) ? 3 : 2;
1315 }
David Hendricks2004b932018-03-09 13:58:27 -08001316 // we have adjusted it, so print it out if verbosity is right
1317 VB_PRT(VBL_TME, "N%d.LMC%d.R%d: adjusting computed vref from %2d (0x%02x) to %2d (0x%02x)\n",
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001318 node, ddr_interface_num, rankx,
David Hendricks2004b932018-03-09 13:58:27 -08001319 saved_final_vref_value, saved_final_vref_value,
1320 computed_final_vref_value, computed_final_vref_value);
David Hendricks7d48ac52018-03-09 14:30:38 -08001321 }
David Hendricks2004b932018-03-09 13:58:27 -08001322 }
1323#endif
1324 return computed_final_vref_value;
1325}
1326
1327static unsigned int EXTR_WR(uint64_t u, int x)
1328{
1329 return (unsigned int)(((u >> (x*12+5)) & 0x3UL) | ((u >> (51+x-2)) & 0x4UL));
1330}
1331static void INSRT_WR(uint64_t *up, int x, int v)
1332{
1333 uint64_t u = *up;
1334 u &= ~(((0x3UL) << (x*12+5)) | ((0x1UL) << (51+x)));
1335 *up = (u | ((v & 0x3UL) << (x*12+5)) | ((v & 0x4UL) << (51+x-2)));
1336 return;
1337}
1338
1339static int encode_row_lsb_ddr3(int row_lsb, int ddr_interface_wide)
1340{
1341 int encoded_row_lsb;
1342 int row_lsb_start = 14;
1343
1344 /* Decoding for row_lsb */
1345 /* 000: row_lsb = mem_adr[14] */
1346 /* 001: row_lsb = mem_adr[15] */
1347 /* 010: row_lsb = mem_adr[16] */
1348 /* 011: row_lsb = mem_adr[17] */
1349 /* 100: row_lsb = mem_adr[18] */
1350 /* 101: row_lsb = mem_adr[19] */
1351 /* 110: row_lsb = mem_adr[20] */
1352 /* 111: RESERVED */
1353
1354 row_lsb_start = 14;
1355
1356 encoded_row_lsb = row_lsb - row_lsb_start ;
1357
1358 return encoded_row_lsb;
1359}
1360
1361static int encode_pbank_lsb_ddr3(int pbank_lsb, int ddr_interface_wide)
1362{
1363 int encoded_pbank_lsb;
1364
1365 /* Decoding for pbank_lsb */
1366 /* 0000:DIMM = mem_adr[28] / rank = mem_adr[27] (if RANK_ENA) */
1367 /* 0001:DIMM = mem_adr[29] / rank = mem_adr[28] " */
1368 /* 0010:DIMM = mem_adr[30] / rank = mem_adr[29] " */
1369 /* 0011:DIMM = mem_adr[31] / rank = mem_adr[30] " */
1370 /* 0100:DIMM = mem_adr[32] / rank = mem_adr[31] " */
1371 /* 0101:DIMM = mem_adr[33] / rank = mem_adr[32] " */
1372 /* 0110:DIMM = mem_adr[34] / rank = mem_adr[33] " */
1373 /* 0111:DIMM = 0 / rank = mem_adr[34] " */
1374 /* 1000-1111: RESERVED */
1375
1376 int pbank_lsb_start = 0;
1377
1378 pbank_lsb_start = 28;
1379
1380 encoded_pbank_lsb = pbank_lsb - pbank_lsb_start;
1381
1382 return encoded_pbank_lsb;
1383}
1384
1385static uint64_t octeon_read_lmcx_ddr3_rlevel_dbg(bdk_node_t node, int ddr_interface_num, int idx)
1386{
1387 DRAM_CSR_MODIFY(c, node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num),
David Hendricks7d48ac52018-03-09 14:30:38 -08001388 c.s.byte = idx);
David Hendricks2004b932018-03-09 13:58:27 -08001389 BDK_CSR_READ(node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num));
1390 BDK_CSR_INIT(rlevel_dbg, node, BDK_LMCX_RLEVEL_DBG(ddr_interface_num));
1391 return rlevel_dbg.s.bitmask;
1392}
1393
1394static uint64_t octeon_read_lmcx_ddr3_wlevel_dbg(bdk_node_t node, int ddr_interface_num, int idx)
1395{
1396 bdk_lmcx_wlevel_dbg_t wlevel_dbg;
1397
1398 wlevel_dbg.u = 0;
1399 wlevel_dbg.s.byte = idx;
1400
1401 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_DBG(ddr_interface_num), wlevel_dbg.u);
1402 BDK_CSR_READ(node, BDK_LMCX_WLEVEL_DBG(ddr_interface_num));
1403
1404 wlevel_dbg.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_DBG(ddr_interface_num));
1405 return wlevel_dbg.s.bitmask;
1406}
1407
1408
1409/*
1410 * Apply a filter to the BITMASK results returned from Octeon
1411 * read-leveling to determine the most likely delay result. This
1412 * computed delay may be used to qualify the delay result returned by
1413 * Octeon. Accumulate an error penalty for invalid characteristics of
1414 * the bitmask so that they can be used to select the most reliable
1415 * results.
1416 *
1417 * The algorithm searches for the largest contiguous MASK within a
1418 * maximum RANGE of bits beginning with the MSB.
1419 *
1420 * 1. a MASK with a WIDTH less than 4 will be penalized
1421 * 2. Bubbles in the bitmask that occur before or after the MASK
1422 * will be penalized
1423 * 3. If there are no trailing bubbles then extra bits that occur
1424 * beyond the maximum RANGE will be penalized.
1425 *
1426 * +++++++++++++++++++++++++++++++++++++++++++++++++++
1427 * + +
1428 * + e.g. bitmask = 27B00 +
1429 * + +
1430 * + 63 +--- mstart 0 +
1431 * + | | | +
1432 * + | +---------+ +--- fb | +
1433 * + | | range | | | +
1434 * + V V V V V +
1435 * + +
1436 * + 0 0 ... 1 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 +
1437 * + +
1438 * + ^ ^ ^ +
1439 * + | | mask| +
1440 * + lb ---+ +-----+ +
1441 * + width +
1442 * + +
1443 * +++++++++++++++++++++++++++++++++++++++++++++++++++
1444 */
1445#define RLEVEL_BITMASK_TRAILING_BITS_ERROR 5
1446#define RLEVEL_BITMASK_BUBBLE_BITS_ERROR 11 // FIXME? now less than TOOLONG
1447#define RLEVEL_BITMASK_NARROW_ERROR 6
1448#define RLEVEL_BITMASK_BLANK_ERROR 100
1449#define RLEVEL_BITMASK_TOOLONG_ERROR 12
1450
1451#define MASKRANGE_BITS 6
1452#define MASKRANGE ((1 << MASKRANGE_BITS) - 1)
1453
1454static int
1455validate_ddr3_rlevel_bitmask(rlevel_bitmask_t *rlevel_bitmask_p, int ddr_type)
1456{
1457 int i;
1458 int errors = 0;
1459 uint64_t mask = 0; /* Used in 64-bit comparisons */
1460 int8_t mstart = 0;
1461 uint8_t width = 0;
1462 uint8_t firstbit = 0;
1463 uint8_t lastbit = 0;
1464 uint8_t bubble = 0;
1465 uint8_t tbubble = 0;
1466 uint8_t blank = 0;
1467 uint8_t narrow = 0;
1468 uint8_t trailing = 0;
1469 uint64_t bitmask = rlevel_bitmask_p->bm;
1470 uint8_t extras = 0;
1471 uint8_t toolong = 0;
1472 uint64_t temp;
1473
1474 if (bitmask == 0) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001475 blank += RLEVEL_BITMASK_BLANK_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08001476 } else {
1477
David Hendricks7d48ac52018-03-09 14:30:38 -08001478 /* Look for fb, the first bit */
David Hendricks2004b932018-03-09 13:58:27 -08001479 temp = bitmask;
1480 while (!(temp & 1)) {
1481 firstbit++;
1482 temp >>= 1;
1483 }
1484
David Hendricks7d48ac52018-03-09 14:30:38 -08001485 /* Look for lb, the last bit */
David Hendricks2004b932018-03-09 13:58:27 -08001486 lastbit = firstbit;
1487 while ((temp >>= 1))
1488 lastbit++;
1489
David Hendricks7d48ac52018-03-09 14:30:38 -08001490 /* Start with the max range to try to find the largest mask within the bitmask data */
David Hendricks2004b932018-03-09 13:58:27 -08001491 width = MASKRANGE_BITS;
1492 for (mask = MASKRANGE; mask > 0; mask >>= 1, --width) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001493 for (mstart = lastbit - width + 1; mstart >= firstbit; --mstart) {
David Hendricks2004b932018-03-09 13:58:27 -08001494 temp = mask << mstart;
David Hendricks7d48ac52018-03-09 14:30:38 -08001495 if ((bitmask & temp) == temp)
David Hendricks2004b932018-03-09 13:58:27 -08001496 goto done_now;
David Hendricks7d48ac52018-03-09 14:30:38 -08001497 }
David Hendricks2004b932018-03-09 13:58:27 -08001498 }
1499 done_now:
1500 /* look for any more contiguous 1's to the right of mstart */
1501 if (width == MASKRANGE_BITS) { // only when maximum mask
1502 while ((bitmask >> (mstart - 1)) & 1) { // slide right over more 1's
1503 --mstart;
1504 if (ddr_type == DDR4_DRAM) // only for DDR4
1505 extras++; // count the number of extra bits
1506 }
1507 }
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001508
David Hendricks2004b932018-03-09 13:58:27 -08001509 /* Penalize any extra 1's beyond the maximum desired mask */
1510 if (extras > 0)
1511 toolong = RLEVEL_BITMASK_TOOLONG_ERROR * ((1 << extras) - 1);
1512
David Hendricks7d48ac52018-03-09 14:30:38 -08001513 /* Detect if bitmask is too narrow. */
1514 if (width < 4)
1515 narrow = (4 - width) * RLEVEL_BITMASK_NARROW_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08001516
David Hendricks7d48ac52018-03-09 14:30:38 -08001517 /* detect leading bubble bits, that is, any 0's between first and mstart */
David Hendricks2004b932018-03-09 13:58:27 -08001518 temp = bitmask >> (firstbit + 1);
1519 i = mstart - firstbit - 1;
1520 while (--i >= 0) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001521 if ((temp & 1) == 0)
1522 bubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08001523 temp >>= 1;
1524 }
1525
1526 temp = bitmask >> (mstart + width + extras);
1527 i = lastbit - (mstart + width + extras - 1);
1528 while (--i >= 0) {
1529 if (temp & 1) { /* Detect 1 bits after the trailing end of the mask, including last. */
1530 trailing += RLEVEL_BITMASK_TRAILING_BITS_ERROR;
1531 } else { /* Detect trailing bubble bits, that is, any 0's between end-of-mask and last */
David Hendricks7d48ac52018-03-09 14:30:38 -08001532 tbubble += RLEVEL_BITMASK_BUBBLE_BITS_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08001533 }
1534 temp >>= 1;
1535 }
1536 }
1537
1538 errors = bubble + tbubble + blank + narrow + trailing + toolong;
1539
1540 /* Pass out useful statistics */
1541 rlevel_bitmask_p->mstart = mstart;
1542 rlevel_bitmask_p->width = width;
1543
David Hendricks7d48ac52018-03-09 14:30:38 -08001544 VB_PRT(VBL_DEV2, "bm:%08lx mask:%02llx, width:%2u, mstart:%2d, fb:%2u, lb:%2u"
David Hendricks2004b932018-03-09 13:58:27 -08001545 " (bu:%2d, tb:%2d, bl:%2d, n:%2d, t:%2d, x:%2d) errors:%3d %s\n",
1546 (unsigned long) bitmask, mask, width, mstart,
1547 firstbit, lastbit, bubble, tbubble, blank, narrow,
1548 trailing, toolong, errors, (errors) ? "=> invalid" : "");
1549
1550 return errors;
1551}
1552
1553static int compute_ddr3_rlevel_delay(uint8_t mstart, uint8_t width, bdk_lmcx_rlevel_ctl_t rlevel_ctl)
1554{
1555 int delay;
1556
1557 debug_bitmask_print(" offset_en:%d", rlevel_ctl.cn8.offset_en);
1558
1559 if (rlevel_ctl.s.offset_en) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001560 delay = max(mstart, mstart + width - 1 - rlevel_ctl.s.offset);
David Hendricks2004b932018-03-09 13:58:27 -08001561 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001562 /* if (rlevel_ctl.s.offset) { */ /* Experimental */
1563 if (0) {
1564 delay = max(mstart + rlevel_ctl.s.offset, mstart + 1);
1565 /* Insure that the offset delay falls within the bitmask */
1566 delay = min(delay, mstart + width-1);
1567 } else {
1568 delay = (width - 1) / 2 + mstart; /* Round down */
1569 /* delay = (width/2) + mstart; */ /* Round up */
1570 }
David Hendricks2004b932018-03-09 13:58:27 -08001571 }
1572
1573 return delay;
1574}
1575
1576#define WLEVEL_BYTE_BITS 5
1577#define WLEVEL_BYTE_MSK ((1UL << 5) - 1)
1578
1579static void update_wlevel_rank_struct(bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08001580 int byte, int delay)
David Hendricks2004b932018-03-09 13:58:27 -08001581{
1582 bdk_lmcx_wlevel_rankx_t temp_wlevel_rank;
1583 if (byte >= 0 && byte <= 8) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001584 temp_wlevel_rank.u = lmc_wlevel_rank->u;
1585 temp_wlevel_rank.u &= ~(WLEVEL_BYTE_MSK << (WLEVEL_BYTE_BITS * byte));
1586 temp_wlevel_rank.u |= ((delay & WLEVEL_BYTE_MSK) << (WLEVEL_BYTE_BITS * byte));
1587 lmc_wlevel_rank->u = temp_wlevel_rank.u;
David Hendricks2004b932018-03-09 13:58:27 -08001588 }
1589}
1590
1591static int get_wlevel_rank_struct(bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08001592 int byte)
David Hendricks2004b932018-03-09 13:58:27 -08001593{
1594 int delay = 0;
1595 if (byte >= 0 && byte <= 8) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001596 delay = ((lmc_wlevel_rank->u) >> (WLEVEL_BYTE_BITS * byte)) & WLEVEL_BYTE_MSK;
David Hendricks2004b932018-03-09 13:58:27 -08001597 }
1598 return delay;
1599}
1600
1601#if 0
1602// entry = 1 is valid, entry = 0 is invalid
1603static int
1604validity_matrix[4][4] = {[0] {1,1,1,0}, // valid pairs when cv == 0: 0,0 + 0,1 + 0,2 == "7"
David Hendricks7d48ac52018-03-09 14:30:38 -08001605 [1] {0,1,1,1}, // valid pairs when cv == 1: 1,1 + 1,2 + 1,3 == "E"
1606 [2] {1,0,1,1}, // valid pairs when cv == 2: 2,2 + 2,3 + 2,0 == "D"
1607 [3] {1,1,0,1}}; // valid pairs when cv == 3: 3,3 + 3,0 + 3,1 == "B"
David Hendricks2004b932018-03-09 13:58:27 -08001608#endif
1609static int
1610validate_seq(int *wl, int *seq)
1611{
1612 int seqx; // sequence index, step through the sequence array
1613 int bitnum;
1614 seqx = 0;
1615 while (seq[seqx+1] >= 0) { // stop on next seq entry == -1
David Hendricks7d48ac52018-03-09 14:30:38 -08001616 // but now, check current versus next
David Hendricks2004b932018-03-09 13:58:27 -08001617#if 0
David Hendricks7d48ac52018-03-09 14:30:38 -08001618 if ( !validity_matrix [wl[seq[seqx]]] [wl[seq[seqx+1]]] )
1619 return 1;
David Hendricks2004b932018-03-09 13:58:27 -08001620#else
David Hendricks7d48ac52018-03-09 14:30:38 -08001621 bitnum = (wl[seq[seqx]] << 2) | wl[seq[seqx+1]];
1622 if (!((1 << bitnum) & 0xBDE7)) // magic validity number (see matrix above)
1623 return 1;
David Hendricks2004b932018-03-09 13:58:27 -08001624#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08001625 seqx++;
David Hendricks2004b932018-03-09 13:58:27 -08001626 }
1627 return 0;
1628}
1629
1630static int
1631Validate_HW_WL_Settings(bdk_node_t node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -08001632 bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank,
David Hendricks2004b932018-03-09 13:58:27 -08001633 int ecc_ena)
1634{
1635 int wl[9], byte, errors;
1636
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001637 // arrange the sequences so
David Hendricks2004b932018-03-09 13:58:27 -08001638 int useq[] = { 0,1,2,3,8,4,5,6,7,-1 }; // index 0 has byte 0, etc, ECC in middle
1639 int rseq1[] = { 8,3,2,1,0,-1 }; // index 0 is ECC, then go down
1640 int rseq2[] = { 4,5,6,7,-1 }; // index 0 has byte 4, then go up
1641 int useqno[] = { 0,1,2,3,4,5,6,7,-1 }; // index 0 has byte 0, etc, no ECC
1642 int rseq1no[] = { 3,2,1,0,-1 }; // index 0 is byte 3, then go down, no ECC
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001643
David Hendricks2004b932018-03-09 13:58:27 -08001644 // in the CSR, bytes 0-7 are always data, byte 8 is ECC
1645 for (byte = 0; byte < 8+ecc_ena; byte++) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001646 wl[byte] = (get_wlevel_rank_struct(lmc_wlevel_rank, byte) >> 1) & 3; // preprocess :-)
David Hendricks2004b932018-03-09 13:58:27 -08001647 }
1648
1649 errors = 0;
1650 if (__bdk_dram_is_rdimm(node, 0) != 0) { // RDIMM order
David Hendricks7d48ac52018-03-09 14:30:38 -08001651 errors = validate_seq(wl, (ecc_ena) ? rseq1 : rseq1no);
1652 errors += validate_seq(wl, rseq2);
David Hendricks2004b932018-03-09 13:58:27 -08001653 } else { // UDIMM order
David Hendricks7d48ac52018-03-09 14:30:38 -08001654 errors = validate_seq(wl, (ecc_ena) ? useq : useqno);
David Hendricks2004b932018-03-09 13:58:27 -08001655 }
1656
1657 return errors;
1658}
1659
1660#define RLEVEL_BYTE_BITS 6
1661#define RLEVEL_BYTE_MSK ((1UL << 6) - 1)
1662
1663static void update_rlevel_rank_struct(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08001664 int byte, int delay)
David Hendricks2004b932018-03-09 13:58:27 -08001665{
1666 bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
1667 if (byte >= 0 && byte <= 8) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001668 temp_rlevel_rank.u = lmc_rlevel_rank->u & ~(RLEVEL_BYTE_MSK << (RLEVEL_BYTE_BITS * byte));
1669 temp_rlevel_rank.u |= ((delay & RLEVEL_BYTE_MSK) << (RLEVEL_BYTE_BITS * byte));
1670 lmc_rlevel_rank->u = temp_rlevel_rank.u;
David Hendricks2004b932018-03-09 13:58:27 -08001671 }
1672}
1673
1674#if RLEXTRAS_PATCH || !DISABLE_SW_WL_PASS_2
1675static int get_rlevel_rank_struct(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08001676 int byte)
David Hendricks2004b932018-03-09 13:58:27 -08001677{
1678 int delay = 0;
1679 if (byte >= 0 && byte <= 8) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001680 delay = ((lmc_rlevel_rank->u) >> (RLEVEL_BYTE_BITS * byte)) & RLEVEL_BYTE_MSK;
David Hendricks2004b932018-03-09 13:58:27 -08001681 }
1682 return delay;
1683}
1684#endif
1685
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001686static void unpack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
David Hendricks7d48ac52018-03-09 14:30:38 -08001687 rlevel_byte_data_t *rlevel_byte,
1688 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank)
David Hendricks2004b932018-03-09 13:58:27 -08001689{
1690 if ((ddr_interface_bytemask & 0xff) == 0xff) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001691 if (ecc_ena) {
1692 rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte7;
1693 rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte6;
1694 rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte5;
1695 rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte4;
1696 rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte8; /* ECC */
1697 } else {
1698 rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7;
1699 rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6;
1700 rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5;
1701 rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4;
1702 }
David Hendricks2004b932018-03-09 13:58:27 -08001703 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001704 rlevel_byte[8].delay = lmc_rlevel_rank.cn83xx.byte8; /* unused */
1705 rlevel_byte[7].delay = lmc_rlevel_rank.cn83xx.byte7; /* unused */
1706 rlevel_byte[6].delay = lmc_rlevel_rank.cn83xx.byte6; /* unused */
1707 rlevel_byte[5].delay = lmc_rlevel_rank.cn83xx.byte5; /* unused */
1708 rlevel_byte[4].delay = lmc_rlevel_rank.cn83xx.byte4; /* ECC */
David Hendricks2004b932018-03-09 13:58:27 -08001709 }
1710 rlevel_byte[3].delay = lmc_rlevel_rank.cn83xx.byte3;
1711 rlevel_byte[2].delay = lmc_rlevel_rank.cn83xx.byte2;
1712 rlevel_byte[1].delay = lmc_rlevel_rank.cn83xx.byte1;
1713 rlevel_byte[0].delay = lmc_rlevel_rank.cn83xx.byte0;
1714}
1715
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001716static void pack_rlevel_settings(int ddr_interface_bytemask, int ecc_ena,
David Hendricks7d48ac52018-03-09 14:30:38 -08001717 rlevel_byte_data_t *rlevel_byte,
1718 bdk_lmcx_rlevel_rankx_t *final_rlevel_rank)
David Hendricks2004b932018-03-09 13:58:27 -08001719{
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001720 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank = *final_rlevel_rank;
David Hendricks2004b932018-03-09 13:58:27 -08001721
1722 if ((ddr_interface_bytemask & 0xff) == 0xff) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001723 if (ecc_ena) {
1724 lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[8].delay;
1725 lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[7].delay;
1726 lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[6].delay;
1727 lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[5].delay;
1728 lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[4].delay; /* ECC */
1729 } else {
1730 lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
1731 lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
1732 lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
1733 lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
1734 }
David Hendricks2004b932018-03-09 13:58:27 -08001735 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001736 lmc_rlevel_rank.cn83xx.byte8 = rlevel_byte[8].delay;
1737 lmc_rlevel_rank.cn83xx.byte7 = rlevel_byte[7].delay;
1738 lmc_rlevel_rank.cn83xx.byte6 = rlevel_byte[6].delay;
1739 lmc_rlevel_rank.cn83xx.byte5 = rlevel_byte[5].delay;
1740 lmc_rlevel_rank.cn83xx.byte4 = rlevel_byte[4].delay;
David Hendricks2004b932018-03-09 13:58:27 -08001741 }
1742 lmc_rlevel_rank.cn83xx.byte3 = rlevel_byte[3].delay;
1743 lmc_rlevel_rank.cn83xx.byte2 = rlevel_byte[2].delay;
1744 lmc_rlevel_rank.cn83xx.byte1 = rlevel_byte[1].delay;
1745 lmc_rlevel_rank.cn83xx.byte0 = rlevel_byte[0].delay;
1746
1747 *final_rlevel_rank = lmc_rlevel_rank;
1748}
1749
1750#if !DISABLE_SW_WL_PASS_2
1751static void rlevel_to_wlevel(bdk_lmcx_rlevel_rankx_t *lmc_rlevel_rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08001752 bdk_lmcx_wlevel_rankx_t *lmc_wlevel_rank, int byte)
David Hendricks2004b932018-03-09 13:58:27 -08001753{
1754 int byte_delay = get_rlevel_rank_struct(lmc_rlevel_rank, byte);
1755
1756 debug_print("Estimating Wlevel delay byte %d: ", byte);
1757 debug_print("Rlevel=%d => ", byte_delay);
1758 byte_delay = divide_roundup(byte_delay,2) & 0x1e;
1759 debug_print("Wlevel=%d\n", byte_delay);
1760 update_wlevel_rank_struct(lmc_wlevel_rank, byte, byte_delay);
1761}
1762#endif /* !DISABLE_SW_WL_PASS_2 */
1763
1764/* Delay trend: constant=0, decreasing=-1, increasing=1 */
1765static int calc_delay_trend(int v)
1766{
1767 if (v == 0)
David Hendricks7d48ac52018-03-09 14:30:38 -08001768 return (0);
David Hendricks2004b932018-03-09 13:58:27 -08001769 if (v < 0)
David Hendricks7d48ac52018-03-09 14:30:38 -08001770 return (-1);
David Hendricks2004b932018-03-09 13:58:27 -08001771 return 1;
1772}
1773
1774/* Evaluate delay sequence across the whole range of byte delays while
1775** keeping track of the overall delay trend, increasing or decreasing.
1776** If the trend changes charge an error amount to the score.
1777*/
1778
1779// NOTE: "max_adj_delay_inc" argument is, by default, 1 for DDR3 and 2 for DDR4
1780
1781static int nonsequential_delays(rlevel_byte_data_t *rlevel_byte,
David Hendricks7d48ac52018-03-09 14:30:38 -08001782 int start, int end, int max_adj_delay_inc)
David Hendricks2004b932018-03-09 13:58:27 -08001783{
1784 int error = 0;
1785 int delay_trend, prev_trend = 0;
1786 int byte_idx;
1787 int delay_inc;
1788 int delay_diff;
1789 int byte_err;
1790
1791 for (byte_idx = start; byte_idx < end; ++byte_idx) {
1792 byte_err = 0;
1793
David Hendricks7d48ac52018-03-09 14:30:38 -08001794 delay_diff = rlevel_byte[byte_idx+1].delay - rlevel_byte[byte_idx].delay;
1795 delay_trend = calc_delay_trend(delay_diff);
1796
1797 debug_bitmask_print("Byte %d: %2d, Byte %d: %2d, delay_trend: %2d, prev_trend: %2d",
1798 byte_idx+0, rlevel_byte[byte_idx+0].delay,
1799 byte_idx+1, rlevel_byte[byte_idx+1].delay,
1800 delay_trend, prev_trend);
David Hendricks2004b932018-03-09 13:58:27 -08001801
1802 /* Increment error each time the trend changes to the opposite direction.
1803 */
David Hendricks7d48ac52018-03-09 14:30:38 -08001804 if ((prev_trend != 0) && (delay_trend != 0) && (prev_trend != delay_trend)) {
1805 byte_err += RLEVEL_NONSEQUENTIAL_DELAY_ERROR;
1806 prev_trend = delay_trend;
1807 debug_bitmask_print(" => Nonsequential byte delay");
1808 }
David Hendricks2004b932018-03-09 13:58:27 -08001809
David Hendricks7d48ac52018-03-09 14:30:38 -08001810 delay_inc = _abs(delay_diff); // how big was the delay change, if any
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001811
David Hendricks2004b932018-03-09 13:58:27 -08001812 /* Even if the trend did not change to the opposite direction, check for
1813 the magnitude of the change, and scale the penalty by the amount that
1814 the size is larger than the provided limit.
1815 */
David Hendricks7d48ac52018-03-09 14:30:38 -08001816 if ((max_adj_delay_inc != 0) && (delay_inc > max_adj_delay_inc)) {
1817 byte_err += (delay_inc - max_adj_delay_inc) * RLEVEL_ADJACENT_DELAY_ERROR;
1818 debug_bitmask_print(" => Adjacent delay error");
1819 }
David Hendricks2004b932018-03-09 13:58:27 -08001820
David Hendricks7d48ac52018-03-09 14:30:38 -08001821 debug_bitmask_print("\n");
1822 if (delay_trend != 0)
1823 prev_trend = delay_trend;
David Hendricks2004b932018-03-09 13:58:27 -08001824
1825 rlevel_byte[byte_idx+1].sqerrs = byte_err;
1826 error += byte_err;
1827 }
1828 return error;
1829}
1830
1831static int roundup_ddr3_wlevel_bitmask(int bitmask)
1832{
1833 int shifted_bitmask;
1834 int leader;
1835 int delay;
1836
1837 for (leader=0; leader<8; ++leader) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001838 shifted_bitmask = (bitmask>>leader);
1839 if ((shifted_bitmask&1) == 0)
1840 break;
David Hendricks2004b932018-03-09 13:58:27 -08001841 }
1842
1843 for (/*leader=leader*/; leader<16; ++leader) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001844 shifted_bitmask = (bitmask>>(leader%8));
1845 if (shifted_bitmask&1)
1846 break;
David Hendricks2004b932018-03-09 13:58:27 -08001847 }
1848
1849 delay = (leader & 1) ? leader + 1 : leader;
1850 delay = delay % 8;
1851
1852 return delay;
1853}
1854
1855/* Check to see if any custom offset values are provided */
1856static int is_dll_offset_provided(const int8_t *dll_offset_table)
1857{
1858 int i;
1859 if (dll_offset_table != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001860 for (i=0; i<9; ++i) {
1861 if (dll_offset_table[i] != 0)
1862 return (1);
1863 }
David Hendricks2004b932018-03-09 13:58:27 -08001864 }
1865 return (0);
1866}
1867
1868/////////////////// These are the RLEVEL settings display routines
1869
1870// flags
1871#define WITH_NOTHING 0
1872#define WITH_SCORE 1
1873#define WITH_AVERAGE 2
1874#define WITH_FINAL 4
1875#define WITH_COMPUTE 8
1876static void do_display_RL(bdk_node_t node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -08001877 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank,
1878 int rank, int flags, int score)
David Hendricks2004b932018-03-09 13:58:27 -08001879{
1880 char score_buf[16];
1881 if (flags & WITH_SCORE)
David Hendricks7d48ac52018-03-09 14:30:38 -08001882 snprintf(score_buf, sizeof(score_buf), "(%d)", score);
David Hendricks2004b932018-03-09 13:58:27 -08001883 else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001884 score_buf[0] = ' '; score_buf[1] = 0;
David Hendricks2004b932018-03-09 13:58:27 -08001885 }
1886
David Hendricks7d48ac52018-03-09 14:30:38 -08001887 const char *msg_buf;
David Hendricks2004b932018-03-09 13:58:27 -08001888 char hex_buf[20];
1889 if (flags & WITH_AVERAGE) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001890 msg_buf = " DELAY AVERAGES ";
David Hendricks2004b932018-03-09 13:58:27 -08001891 } else if (flags & WITH_FINAL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001892 msg_buf = " FINAL SETTINGS ";
David Hendricks2004b932018-03-09 13:58:27 -08001893 } else if (flags & WITH_COMPUTE) {
David Hendricks7d48ac52018-03-09 14:30:38 -08001894 msg_buf = " COMPUTED DELAYS ";
David Hendricks2004b932018-03-09 13:58:27 -08001895 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08001896 snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_rlevel_rank.u);
1897 msg_buf = hex_buf;
David Hendricks2004b932018-03-09 13:58:27 -08001898 }
1899
1900 ddr_print("N%d.LMC%d.R%d: Rlevel Rank %#4x, %s : %5d %5d %5d %5d %5d %5d %5d %5d %5d %s\n",
1901 node, ddr_interface_num, rank,
1902 lmc_rlevel_rank.s.status,
1903 msg_buf,
1904 lmc_rlevel_rank.cn83xx.byte8,
1905 lmc_rlevel_rank.cn83xx.byte7,
1906 lmc_rlevel_rank.cn83xx.byte6,
1907 lmc_rlevel_rank.cn83xx.byte5,
1908 lmc_rlevel_rank.cn83xx.byte4,
1909 lmc_rlevel_rank.cn83xx.byte3,
1910 lmc_rlevel_rank.cn83xx.byte2,
1911 lmc_rlevel_rank.cn83xx.byte1,
1912 lmc_rlevel_rank.cn83xx.byte0,
David Hendricks7d48ac52018-03-09 14:30:38 -08001913 score_buf
David Hendricks2004b932018-03-09 13:58:27 -08001914 );
1915}
1916
1917static inline void
1918display_RL(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank)
1919{
1920 do_display_RL(node, ddr_interface_num, lmc_rlevel_rank, rank, 0, 0);
1921}
1922
1923static inline void
1924display_RL_with_score(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score)
1925{
1926 do_display_RL(node, ddr_interface_num, lmc_rlevel_rank, rank, 1, score);
1927}
1928
1929#if !PICK_BEST_RANK_SCORE_NOT_AVG
1930static inline void
1931display_RL_with_average(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score)
1932{
1933 do_display_RL(node, ddr_interface_num, lmc_rlevel_rank, rank, 3, score);
1934}
1935#endif
1936
1937static inline void
1938display_RL_with_final(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank)
1939{
1940 do_display_RL(node, ddr_interface_num, lmc_rlevel_rank, rank, 4, 0);
1941}
1942
1943static inline void
1944display_RL_with_computed(bdk_node_t node, int ddr_interface_num, bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score)
1945{
1946 do_display_RL(node, ddr_interface_num, lmc_rlevel_rank, rank, 9, score);
1947}
1948
1949// flag values
1950#define WITH_RODT_BLANK 0
1951#define WITH_RODT_SKIPPING 1
1952#define WITH_RODT_BESTROW 2
1953#define WITH_RODT_BESTSCORE 3
1954// control
1955#define SKIP_SKIPPING 1
1956
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001957static const char *with_rodt_canned_msgs[4] = { " ", "SKIPPING ", "BEST ROW ", "BEST SCORE" };
David Hendricks2004b932018-03-09 13:58:27 -08001958
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001959static void display_RL_with_RODT(bdk_node_t node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -08001960 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank, int rank, int score,
1961 int nom_ohms, int rodt_ohms, int flag)
David Hendricks2004b932018-03-09 13:58:27 -08001962{
1963 const char *msg_buf;
1964 char set_buf[20];
1965#if SKIP_SKIPPING
1966 if (flag == WITH_RODT_SKIPPING) return;
1967#endif
1968 msg_buf = with_rodt_canned_msgs[flag];
1969 if (nom_ohms < 0) {
1970 snprintf(set_buf, sizeof(set_buf), " RODT %3d ", rodt_ohms);
1971 } else {
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001972 snprintf(set_buf, sizeof(set_buf), "NOM %3d RODT %3d", nom_ohms, rodt_ohms);
David Hendricks2004b932018-03-09 13:58:27 -08001973 }
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01001974
David Hendricks2004b932018-03-09 13:58:27 -08001975 VB_PRT(VBL_TME, "N%d.LMC%d.R%d: Rlevel %s %s : %5d %5d %5d %5d %5d %5d %5d %5d %5d (%d)\n",
1976 node, ddr_interface_num, rank,
1977 set_buf, msg_buf,
1978 lmc_rlevel_rank.cn83xx.byte8,
1979 lmc_rlevel_rank.cn83xx.byte7,
1980 lmc_rlevel_rank.cn83xx.byte6,
1981 lmc_rlevel_rank.cn83xx.byte5,
1982 lmc_rlevel_rank.cn83xx.byte4,
1983 lmc_rlevel_rank.cn83xx.byte3,
1984 lmc_rlevel_rank.cn83xx.byte2,
1985 lmc_rlevel_rank.cn83xx.byte1,
1986 lmc_rlevel_rank.cn83xx.byte0,
1987 score
1988 );
1989
1990 // FIXME: does this help make the output a little easier to focus?
1991 if (flag == WITH_RODT_BESTSCORE) {
1992 VB_PRT(VBL_DEV, "-----------\n");
1993 }
1994}
1995
1996static void
1997do_display_WL(bdk_node_t node, int ddr_interface_num, bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank, int rank, int flags)
1998{
David Hendricks7d48ac52018-03-09 14:30:38 -08001999 const char *msg_buf;
David Hendricks2004b932018-03-09 13:58:27 -08002000 char hex_buf[20];
2001 int vbl;
2002 if (flags & WITH_FINAL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08002003 msg_buf = " FINAL SETTINGS ";
David Hendricks2004b932018-03-09 13:58:27 -08002004 vbl = VBL_NORM;
2005 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08002006 snprintf(hex_buf, sizeof(hex_buf), "0x%016lX", lmc_wlevel_rank.u);
2007 msg_buf = hex_buf;
David Hendricks2004b932018-03-09 13:58:27 -08002008 vbl = VBL_FAE;
2009 }
2010
2011 VB_PRT(vbl, "N%d.LMC%d.R%d: Wlevel Rank %#4x, %s : %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
2012 node, ddr_interface_num, rank,
2013 lmc_wlevel_rank.s.status,
2014 msg_buf,
2015 lmc_wlevel_rank.s.byte8,
2016 lmc_wlevel_rank.s.byte7,
2017 lmc_wlevel_rank.s.byte6,
2018 lmc_wlevel_rank.s.byte5,
2019 lmc_wlevel_rank.s.byte4,
2020 lmc_wlevel_rank.s.byte3,
2021 lmc_wlevel_rank.s.byte2,
2022 lmc_wlevel_rank.s.byte1,
2023 lmc_wlevel_rank.s.byte0
2024 );
2025}
2026
2027static inline void
2028display_WL(bdk_node_t node, int ddr_interface_num, bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank, int rank)
2029{
2030 do_display_WL(node, ddr_interface_num, lmc_wlevel_rank, rank, WITH_NOTHING);
2031}
2032
2033static inline void
2034display_WL_with_final(bdk_node_t node, int ddr_interface_num, bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank, int rank)
2035{
2036 do_display_WL(node, ddr_interface_num, lmc_wlevel_rank, rank, WITH_FINAL);
2037}
2038
2039// pretty-print bitmask adjuster
2040static uint64_t
2041PPBM(uint64_t bm)
2042{
2043 if (bm != 0ul) {
2044 while ((bm & 0x0fful) == 0ul)
2045 bm >>= 4;
2046 }
2047 return bm;
2048}
2049
2050// xlate PACKED index to UNPACKED index to use with rlevel_byte
2051#define XPU(i,e) (((i) < 4)?(i):((i)<8)?(i)+(e):4)
2052// xlate UNPACKED index to PACKED index to use with rlevel_bitmask
2053#define XUP(i,e) (((i) < 4)?(i):((i)>4)?(i)-(e):8)
2054
2055// flag values
2056#define WITH_WL_BITMASKS 0
2057#define WITH_RL_BITMASKS 1
2058#define WITH_RL_MASK_SCORES 2
2059#define WITH_RL_SEQ_SCORES 3
2060static void
2061do_display_BM(bdk_node_t node, int ddr_interface_num, int rank, void *bm, int flags, int ecc_ena)
2062{
2063 int ecc = !!ecc_ena;
2064 if (flags == WITH_WL_BITMASKS) { // wlevel_bitmask array in PACKED index order, so just print them
2065 int *bitmasks = (int *)bm;
2066
2067 ddr_print("N%d.LMC%d.R%d: Wlevel Debug Results : %05x %05x %05x %05x %05x %05x %05x %05x %05x\n",
2068 node, ddr_interface_num, rank,
2069 bitmasks[8],
2070 bitmasks[7],
2071 bitmasks[6],
2072 bitmasks[5],
2073 bitmasks[4],
2074 bitmasks[3],
2075 bitmasks[2],
2076 bitmasks[1],
2077 bitmasks[0]
2078 );
2079 } else
2080 if (flags == WITH_RL_BITMASKS) { // rlevel_bitmask array in PACKED index order, so just print them
2081 rlevel_bitmask_t *rlevel_bitmask = (rlevel_bitmask_t *)bm;
David Hendricks7d48ac52018-03-09 14:30:38 -08002082 ddr_print("N%d.LMC%d.R%d: Rlevel Debug Bitmasks 8:0 : %05llx %05llx %05llx %05llx %05llx %05llx %05llx %05llx %05llx\n",
David Hendricks2004b932018-03-09 13:58:27 -08002083 node, ddr_interface_num, rank,
2084 PPBM(rlevel_bitmask[8].bm),
2085 PPBM(rlevel_bitmask[7].bm),
2086 PPBM(rlevel_bitmask[6].bm),
2087 PPBM(rlevel_bitmask[5].bm),
2088 PPBM(rlevel_bitmask[4].bm),
2089 PPBM(rlevel_bitmask[3].bm),
2090 PPBM(rlevel_bitmask[2].bm),
2091 PPBM(rlevel_bitmask[1].bm),
2092 PPBM(rlevel_bitmask[0].bm)
2093 );
2094 } else
2095 if (flags == WITH_RL_MASK_SCORES) { // rlevel_bitmask array in PACKED index order, so just print them
2096 rlevel_bitmask_t *rlevel_bitmask = (rlevel_bitmask_t *)bm;
2097 ddr_print("N%d.LMC%d.R%d: Rlevel Debug Bitmask Scores 8:0 : %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
2098 node, ddr_interface_num, rank,
2099 rlevel_bitmask[8].errs,
2100 rlevel_bitmask[7].errs,
2101 rlevel_bitmask[6].errs,
2102 rlevel_bitmask[5].errs,
2103 rlevel_bitmask[4].errs,
2104 rlevel_bitmask[3].errs,
2105 rlevel_bitmask[2].errs,
2106 rlevel_bitmask[1].errs,
2107 rlevel_bitmask[0].errs
2108 );
2109 } else
2110 if (flags == WITH_RL_SEQ_SCORES) { // rlevel_byte array in UNPACKED index order, so xlate and print them
2111 rlevel_byte_data_t *rlevel_byte = (rlevel_byte_data_t *)bm;
2112 ddr_print("N%d.LMC%d.R%d: Rlevel Debug Non-seq Scores 8:0 : %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
2113 node, ddr_interface_num, rank,
2114 rlevel_byte[XPU(8,ecc)].sqerrs,
2115 rlevel_byte[XPU(7,ecc)].sqerrs,
2116 rlevel_byte[XPU(6,ecc)].sqerrs,
2117 rlevel_byte[XPU(5,ecc)].sqerrs,
2118 rlevel_byte[XPU(4,ecc)].sqerrs,
2119 rlevel_byte[XPU(3,ecc)].sqerrs,
2120 rlevel_byte[XPU(2,ecc)].sqerrs,
2121 rlevel_byte[XPU(1,ecc)].sqerrs,
2122 rlevel_byte[XPU(0,ecc)].sqerrs
2123 );
2124 }
2125}
2126
2127static inline void
2128display_WL_BM(bdk_node_t node, int ddr_interface_num, int rank, int *bitmasks)
2129{
2130 do_display_BM(node, ddr_interface_num, rank, (void *)bitmasks, WITH_WL_BITMASKS, 0);
2131}
2132
2133static inline void
2134display_RL_BM(bdk_node_t node, int ddr_interface_num, int rank, rlevel_bitmask_t *bitmasks, int ecc_ena)
2135{
2136 do_display_BM(node, ddr_interface_num, rank, (void *)bitmasks, WITH_RL_BITMASKS, ecc_ena);
2137}
2138
2139static inline void
2140display_RL_BM_scores(bdk_node_t node, int ddr_interface_num, int rank, rlevel_bitmask_t *bitmasks, int ecc_ena)
2141{
2142 do_display_BM(node, ddr_interface_num, rank, (void *)bitmasks, WITH_RL_MASK_SCORES, ecc_ena);
2143}
2144
2145static inline void
2146display_RL_SEQ_scores(bdk_node_t node, int ddr_interface_num, int rank, rlevel_byte_data_t *bytes, int ecc_ena)
2147{
2148 do_display_BM(node, ddr_interface_num, rank, (void *)bytes, WITH_RL_SEQ_SCORES, ecc_ena);
2149}
2150
2151unsigned short load_dll_offset(bdk_node_t node, int ddr_interface_num,
David Hendricks7d48ac52018-03-09 14:30:38 -08002152 int dll_offset_mode, int byte_offset, int byte)
David Hendricks2004b932018-03-09 13:58:27 -08002153{
2154 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
2155 /* byte_sel:
2156 0x1 = byte 0, ..., 0x9 = byte 8
2157 0xA = all bytes */
2158 int byte_sel = (byte == 10) ? byte : byte + 1;
2159
2160 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2161 SET_DDR_DLL_CTL3(load_offset, 0);
David Hendricks7d48ac52018-03-09 14:30:38 -08002162 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08002163 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2164
2165 SET_DDR_DLL_CTL3(mode_sel, dll_offset_mode);
2166 SET_DDR_DLL_CTL3(offset, (_abs(byte_offset)&0x3f) | (_sign(byte_offset) << 6)); /* Always 6-bit field? */
2167 SET_DDR_DLL_CTL3(byte_sel, byte_sel);
David Hendricks7d48ac52018-03-09 14:30:38 -08002168 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08002169 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2170
2171 SET_DDR_DLL_CTL3(load_offset, 1);
David Hendricks7d48ac52018-03-09 14:30:38 -08002172 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08002173 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2174
2175 return ((unsigned short) GET_DDR_DLL_CTL3(offset));
2176}
2177
2178void change_dll_offset_enable(bdk_node_t node, int ddr_interface_num, int change)
2179{
2180 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
2181
2182 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2183 SET_DDR_DLL_CTL3(offset_ena, !!change);
David Hendricks7d48ac52018-03-09 14:30:38 -08002184 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08002185 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
2186}
2187
2188static void process_custom_dll_offsets(bdk_node_t node, int ddr_interface_num, const char *enable_str,
David Hendricks7d48ac52018-03-09 14:30:38 -08002189 const int8_t *offsets, const char *byte_str, int mode)
David Hendricks2004b932018-03-09 13:58:27 -08002190{
2191 const char *s;
2192 int enabled;
2193 int provided;
2194
2195 if ((s = lookup_env_parameter("%s", enable_str)) != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08002196 enabled = !!strtol(s, NULL, 0);
David Hendricks2004b932018-03-09 13:58:27 -08002197 } else
David Hendricks7d48ac52018-03-09 14:30:38 -08002198 enabled = -1;
David Hendricks2004b932018-03-09 13:58:27 -08002199
2200 // enabled == -1: no override, do only configured offsets if provided
2201 // enabled == 0: override OFF, do NOT do it even if configured offsets provided
2202 // enabled == 1: override ON, do it for overrides plus configured offsets
2203
2204 if (enabled == 0)
David Hendricks7d48ac52018-03-09 14:30:38 -08002205 return;
David Hendricks2004b932018-03-09 13:58:27 -08002206
2207 provided = is_dll_offset_provided(offsets);
2208
2209 if (enabled < 0 && !provided)
David Hendricks7d48ac52018-03-09 14:30:38 -08002210 return;
David Hendricks2004b932018-03-09 13:58:27 -08002211
2212 int byte_offset;
2213 unsigned short offset[9] = {0};
2214 int byte;
2215
2216 // offsets need to be disabled while loading
2217 change_dll_offset_enable(node, ddr_interface_num, 0);
2218
2219 for (byte = 0; byte < 9; ++byte) {
2220
David Hendricks7d48ac52018-03-09 14:30:38 -08002221 // always take the provided, if available
2222 byte_offset = (provided) ? offsets[byte] : 0;
David Hendricks2004b932018-03-09 13:58:27 -08002223
David Hendricks7d48ac52018-03-09 14:30:38 -08002224 // then, if enabled, use any overrides present
2225 if (enabled > 0) {
2226 if ((s = lookup_env_parameter(byte_str, ddr_interface_num, byte)) != NULL) {
David Hendricks2004b932018-03-09 13:58:27 -08002227 byte_offset = strtol(s, NULL, 0);
2228 }
David Hendricks7d48ac52018-03-09 14:30:38 -08002229 }
David Hendricks2004b932018-03-09 13:58:27 -08002230
David Hendricks7d48ac52018-03-09 14:30:38 -08002231 offset[byte] = load_dll_offset(node, ddr_interface_num, mode, byte_offset, byte);
David Hendricks2004b932018-03-09 13:58:27 -08002232 }
2233
2234 // re-enable offsets after loading
2235 change_dll_offset_enable(node, ddr_interface_num, 1);
2236
2237 ddr_print("N%d.LMC%d: DLL %s Offset 8:0 :"
David Hendricks7d48ac52018-03-09 14:30:38 -08002238 " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
2239 node, ddr_interface_num, (mode == 2) ? "Read " : "Write",
2240 offset[8], offset[7], offset[6], offset[5], offset[4],
2241 offset[3], offset[2], offset[1], offset[0]);
David Hendricks2004b932018-03-09 13:58:27 -08002242}
2243
2244void perform_octeon3_ddr3_sequence(bdk_node_t node, int rank_mask, int ddr_interface_num, int sequence)
2245{
2246 /*
2247 * 3. Without changing any other fields in LMC(0)_CONFIG, write
2248 * LMC(0)_CONFIG[RANKMASK] then write both
2249 * LMC(0)_SEQ_CTL[SEQ_SEL,INIT_START] = 1 with a single CSR write
2250 * operation. LMC(0)_CONFIG[RANKMASK] bits should be set to indicate
2251 * the ranks that will participate in the sequence.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002252 *
David Hendricks2004b932018-03-09 13:58:27 -08002253 * The LMC(0)_SEQ_CTL[SEQ_SEL] value should select power-up/init or
2254 * selfrefresh exit, depending on whether the DRAM parts are in
2255 * self-refresh and whether their contents should be preserved. While
2256 * LMC performs these sequences, it will not perform any other DDR3
2257 * transactions. When the sequence is complete, hardware sets the
2258 * LMC(0)_CONFIG[INIT_STATUS] bits for the ranks that have been
2259 * initialized.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002260 *
David Hendricks2004b932018-03-09 13:58:27 -08002261 * If power-up/init is selected immediately following a DRESET
2262 * assertion, LMC executes the sequence described in the "Reset and
2263 * Initialization Procedure" section of the JEDEC DDR3
2264 * specification. This includes activating CKE, writing all four DDR3
2265 * mode registers on all selected ranks, and issuing the required ZQCL
2266 * command. The LMC(0)_CONFIG[RANKMASK] value should select all ranks
2267 * with attached DRAM in this case. If LMC(0)_CONTROL[RDIMM_ENA] = 1,
2268 * LMC writes the JEDEC standard SSTE32882 control words selected by
2269 * LMC(0)_DIMM_CTL[DIMM*_WMASK] between DDR_CKE* signal assertion and
2270 * the first DDR3 mode register write operation.
2271 * LMC(0)_DIMM_CTL[DIMM*_WMASK] should be cleared to 0 if the
2272 * corresponding DIMM is not present.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002273 *
David Hendricks2004b932018-03-09 13:58:27 -08002274 * If self-refresh exit is selected, LMC executes the required SRX
2275 * command followed by a refresh and ZQ calibration. Section 4.5
2276 * describes behavior of a REF + ZQCS. LMC does not write the DDR3
2277 * mode registers as part of this sequence, and the mode register
2278 * parameters must match at self-refresh entry and exit times.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002279 *
David Hendricks2004b932018-03-09 13:58:27 -08002280 * 4. Read LMC(0)_SEQ_CTL and wait for LMC(0)_SEQ_CTL[SEQ_COMPLETE] to be
2281 * set.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002282 *
David Hendricks2004b932018-03-09 13:58:27 -08002283 * 5. Read LMC(0)_CONFIG[INIT_STATUS] and confirm that all ranks have
2284 * been initialized.
2285 */
2286
2287 const char *s;
2288 static const char *sequence_str[] = {
David Hendricks7d48ac52018-03-09 14:30:38 -08002289 "Power-up/init",
2290 "Read-leveling",
2291 "Self-refresh entry",
2292 "Self-refresh exit",
2293 "Illegal",
2294 "Illegal",
2295 "Write-leveling",
2296 "Init Register Control Words",
2297 "Mode Register Write",
2298 "MPR Register Access",
2299 "LMC Deskew/Internal Vref training",
2300 "Offset Training"
David Hendricks2004b932018-03-09 13:58:27 -08002301 };
2302
2303 bdk_lmcx_seq_ctl_t seq_ctl;
2304 bdk_lmcx_config_t lmc_config;
2305
2306 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
2307 lmc_config.s.rankmask = rank_mask;
2308 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
2309
2310 seq_ctl.u = 0;
2311
2312 seq_ctl.s.init_start = 1;
2313 seq_ctl.s.seq_sel = sequence;
2314
2315 VB_PRT(VBL_SEQ, "N%d.LMC%d: Performing LMC sequence=%x: rank_mask=0x%02x, %s\n",
Patrick Rudolph06528d92018-07-12 11:54:20 +02002316 node, ddr_interface_num, sequence, rank_mask, sequence < 12 ? sequence_str[sequence] : "");
David Hendricks2004b932018-03-09 13:58:27 -08002317
2318 if ((s = lookup_env_parameter("ddr_trigger_sequence%d", sequence)) != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08002319 /* FIXME(dhendrix): this appears to be meant for the eval board */
2320#if 0
2321 int trigger = strtoul(s, NULL, 0);
2322 if (trigger)
2323 pulse_gpio_pin(node, 1, 2);
2324#endif
2325 error_print("env parameter ddr_trigger_sequence%d not found\n", sequence);
David Hendricks2004b932018-03-09 13:58:27 -08002326 }
2327
2328 DRAM_CSR_WRITE(node, BDK_LMCX_SEQ_CTL(ddr_interface_num), seq_ctl.u);
2329 BDK_CSR_READ(node, BDK_LMCX_SEQ_CTL(ddr_interface_num));
2330
2331 /* Wait 100us minimum before checking for sequence complete */
2332 bdk_wait_usec(100);
David Hendricks7d48ac52018-03-09 14:30:38 -08002333 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_SEQ_CTL(ddr_interface_num), seq_complete, ==, 1, 1000000))
David Hendricks2004b932018-03-09 13:58:27 -08002334 {
David Hendricks7d48ac52018-03-09 14:30:38 -08002335 error_print("N%d.LMC%d: Timeout waiting for LMC sequence=%x, rank_mask=0x%02x, ignoring...\n",
2336 node, ddr_interface_num, sequence, rank_mask);
David Hendricks2004b932018-03-09 13:58:27 -08002337 }
2338 else {
David Hendricks7d48ac52018-03-09 14:30:38 -08002339 VB_PRT(VBL_SEQ, "N%d.LMC%d: LMC sequence=%x: Completed.\n", node, ddr_interface_num, sequence);
David Hendricks2004b932018-03-09 13:58:27 -08002340 }
2341}
2342
2343void ddr4_mrw(bdk_node_t node, int ddr_interface_num, int rank,
2344 int mr_wr_addr, int mr_wr_sel, int mr_wr_bg1)
2345{
2346 bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
2347
2348 lmc_mr_mpr_ctl.u = 0;
2349 lmc_mr_mpr_ctl.s.mr_wr_addr = (mr_wr_addr == -1) ? 0 : mr_wr_addr;
2350 lmc_mr_mpr_ctl.s.mr_wr_sel = mr_wr_sel;
2351 lmc_mr_mpr_ctl.s.mr_wr_rank = rank;
2352 //lmc_mr_mpr_ctl.s.mr_wr_pda_mask =
2353 //lmc_mr_mpr_ctl.s.mr_wr_pda_enable =
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01002354 //lmc_mr_mpr_ctl.s.mpr_loc =
2355 //lmc_mr_mpr_ctl.s.mpr_wr =
David Hendricks2004b932018-03-09 13:58:27 -08002356 //lmc_mr_mpr_ctl.s.mpr_bit_select =
2357 //lmc_mr_mpr_ctl.s.mpr_byte_select =
2358 //lmc_mr_mpr_ctl.s.mpr_whole_byte_enable =
2359 lmc_mr_mpr_ctl.s.mr_wr_use_default_value = (mr_wr_addr == -1) ? 1 : 0;
2360 lmc_mr_mpr_ctl.s.mr_wr_bg1 = mr_wr_bg1;
2361 DRAM_CSR_WRITE(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num), lmc_mr_mpr_ctl.u);
2362
2363 /* Mode Register Write */
2364 perform_octeon3_ddr3_sequence(node, 1 << rank, ddr_interface_num, 0x8);
2365}
2366
2367#define InvA0_17(x) (x ^ 0x22bf8)
2368static void set_mpr_mode (bdk_node_t node, int rank_mask,
2369 int ddr_interface_num, int dimm_count, int mpr, int bg1)
2370{
2371 int rankx;
2372
2373 ddr_print("All Ranks: Set mpr mode = %x %c-side\n",
2374 mpr, (bg1==0) ? 'A' : 'B');
2375
2376 for (rankx = 0; rankx < dimm_count*4; rankx++) {
2377 if (!(rank_mask & (1 << rankx)))
2378 continue;
2379 if (bg1 == 0)
2380 ddr4_mrw(node, ddr_interface_num, rankx, mpr<<2, 3, bg1); /* MR3 A-side */
2381 else
2382 ddr4_mrw(node, ddr_interface_num, rankx, InvA0_17(mpr<<2), ~3, bg1); /* MR3 B-side */
2383 }
2384}
2385
2386#if ENABLE_DISPLAY_MPR_PAGE
2387static void do_ddr4_mpr_read(bdk_node_t node, int ddr_interface_num, int rank,
2388 int page, int location)
2389{
2390 bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
2391
2392 lmc_mr_mpr_ctl.u = BDK_CSR_READ(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num));
2393
2394 lmc_mr_mpr_ctl.s.mr_wr_addr = 0;
2395 lmc_mr_mpr_ctl.s.mr_wr_sel = page; /* Page */
2396 lmc_mr_mpr_ctl.s.mr_wr_rank = rank;
2397 //lmc_mr_mpr_ctl.s.mr_wr_pda_mask =
2398 //lmc_mr_mpr_ctl.s.mr_wr_pda_enable =
2399 lmc_mr_mpr_ctl.s.mpr_loc = location;
2400 lmc_mr_mpr_ctl.s.mpr_wr = 0; /* Read=0, Write=1 */
2401 //lmc_mr_mpr_ctl.s.mpr_bit_select =
2402 //lmc_mr_mpr_ctl.s.mpr_byte_select =
2403 //lmc_mr_mpr_ctl.s.mpr_whole_byte_enable =
2404 //lmc_mr_mpr_ctl.s.mr_wr_use_default_value =
2405 //lmc_mr_mpr_ctl.s.mr_wr_bg1 =
2406
2407 DRAM_CSR_WRITE(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num), lmc_mr_mpr_ctl.u);
2408
2409 /* MPR register access sequence */
2410 perform_octeon3_ddr3_sequence(node, 1 << rank, ddr_interface_num, 0x9);
2411
2412 debug_print("LMC_MR_MPR_CTL : 0x%016lx\n", lmc_mr_mpr_ctl.u);
2413 debug_print("lmc_mr_mpr_ctl.s.mr_wr_addr: 0x%02x\n", lmc_mr_mpr_ctl.s.mr_wr_addr);
2414 debug_print("lmc_mr_mpr_ctl.s.mr_wr_sel : 0x%02x\n", lmc_mr_mpr_ctl.s.mr_wr_sel);
2415 debug_print("lmc_mr_mpr_ctl.s.mpr_loc : 0x%02x\n", lmc_mr_mpr_ctl.s.mpr_loc);
2416 debug_print("lmc_mr_mpr_ctl.s.mpr_wr : 0x%02x\n", lmc_mr_mpr_ctl.s.mpr_wr);
2417
2418}
2419#endif
2420
David Hendricks7d48ac52018-03-09 14:30:38 -08002421static int set_rdimm_mode(bdk_node_t node, int ddr_interface_num, int enable)
David Hendricks2004b932018-03-09 13:58:27 -08002422{
2423 bdk_lmcx_control_t lmc_control;
2424 int save_rdimm_mode;
2425
2426 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
2427 save_rdimm_mode = lmc_control.s.rdimm_ena;
2428 lmc_control.s.rdimm_ena = enable;
2429 VB_PRT(VBL_FAE, "Setting RDIMM_ENA = %x\n", enable);
2430 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
2431
2432 return (save_rdimm_mode);
2433}
2434
2435#if ENABLE_DISPLAY_MPR_PAGE
2436static void ddr4_mpr_read(bdk_node_t node, int ddr_interface_num, int rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08002437 int page, int location, uint64_t *mpr_data)
David Hendricks2004b932018-03-09 13:58:27 -08002438{
2439 do_ddr4_mpr_read(node, ddr_interface_num, rank, page, location);
2440
2441 mpr_data[0] = BDK_CSR_READ(node, BDK_LMCX_MPR_DATA0(ddr_interface_num));
2442 mpr_data[1] = BDK_CSR_READ(node, BDK_LMCX_MPR_DATA1(ddr_interface_num));
2443 mpr_data[2] = BDK_CSR_READ(node, BDK_LMCX_MPR_DATA2(ddr_interface_num));
2444
2445 debug_print("MPR Read %016lx.%016lx.%016lx\n", mpr_data[2], mpr_data[1], mpr_data[0]);
2446}
2447
2448/* Display MPR values for Page Location */
2449static void Display_MPR_Page_Location(bdk_node_t node, int rank,
2450 int ddr_interface_num, int dimm_count,
2451 int page, int location, uint64_t *mpr_data)
2452{
2453 ddr4_mpr_read(node, ddr_interface_num, rank, page, location, mpr_data);
2454 ddr_print("MPR Page %d, Loc %d %016lx.%016lx.%016lx\n",
2455 page, location, mpr_data[2], mpr_data[1], mpr_data[0]);
2456}
2457
2458/* Display MPR values for Page */
2459static void Display_MPR_Page(bdk_node_t node, int rank_mask,
2460 int ddr_interface_num, int dimm_count, int page)
2461{
2462 int rankx;
2463 uint64_t mpr_data[3];
2464
2465 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
2466 if (!(rank_mask & (1 << rankx)))
2467 continue;
2468
2469 ddr_print("Rank %d: MPR values for Page %d\n", rankx, page);
2470 for (int location = 0; location < 4; location++) {
2471 Display_MPR_Page_Location(node, rankx, ddr_interface_num, dimm_count,
2472 page, location, &mpr_data[0]);
2473 }
2474
2475 } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
2476}
2477#endif
2478
David Hendricks7d48ac52018-03-09 14:30:38 -08002479static void ddr4_mpr_write(bdk_node_t node, int ddr_interface_num, int rank,
David Hendricks2004b932018-03-09 13:58:27 -08002480 int page, int location, uint8_t mpr_data)
2481{
2482 bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
2483
2484 lmc_mr_mpr_ctl.u = 0;
2485 lmc_mr_mpr_ctl.s.mr_wr_addr = mpr_data;
2486 lmc_mr_mpr_ctl.s.mr_wr_sel = page; /* Page */
2487 lmc_mr_mpr_ctl.s.mr_wr_rank = rank;
2488 //lmc_mr_mpr_ctl.s.mr_wr_pda_mask =
2489 //lmc_mr_mpr_ctl.s.mr_wr_pda_enable =
2490 lmc_mr_mpr_ctl.s.mpr_loc = location;
2491 lmc_mr_mpr_ctl.s.mpr_wr = 1; /* Read=0, Write=1 */
2492 //lmc_mr_mpr_ctl.s.mpr_bit_select =
2493 //lmc_mr_mpr_ctl.s.mpr_byte_select =
2494 //lmc_mr_mpr_ctl.s.mpr_whole_byte_enable =
2495 //lmc_mr_mpr_ctl.s.mr_wr_use_default_value =
2496 //lmc_mr_mpr_ctl.s.mr_wr_bg1 =
2497 DRAM_CSR_WRITE(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num), lmc_mr_mpr_ctl.u);
2498
2499 /* MPR register access sequence */
2500 perform_octeon3_ddr3_sequence(node, (1 << rank), ddr_interface_num, 0x9);
2501
2502 debug_print("LMC_MR_MPR_CTL : 0x%016lx\n", lmc_mr_mpr_ctl.u);
2503 debug_print("lmc_mr_mpr_ctl.s.mr_wr_addr: 0x%02x\n", lmc_mr_mpr_ctl.s.mr_wr_addr);
2504 debug_print("lmc_mr_mpr_ctl.s.mr_wr_sel : 0x%02x\n", lmc_mr_mpr_ctl.s.mr_wr_sel);
2505 debug_print("lmc_mr_mpr_ctl.s.mpr_loc : 0x%02x\n", lmc_mr_mpr_ctl.s.mpr_loc);
2506 debug_print("lmc_mr_mpr_ctl.s.mpr_wr : 0x%02x\n", lmc_mr_mpr_ctl.s.mpr_wr);
2507}
2508
2509void set_vref(bdk_node_t node, int ddr_interface_num, int rank,
David Hendricks7d48ac52018-03-09 14:30:38 -08002510 int range, int value)
David Hendricks2004b932018-03-09 13:58:27 -08002511{
2512 bdk_lmcx_mr_mpr_ctl_t lmc_mr_mpr_ctl;
2513 bdk_lmcx_modereg_params3_t lmc_modereg_params3;
2514 int mr_wr_addr = 0;
2515
2516 lmc_mr_mpr_ctl.u = 0;
2517 lmc_modereg_params3.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS3(ddr_interface_num));
2518
2519 mr_wr_addr |= lmc_modereg_params3.s.tccd_l<<10; /* A12:A10 tCCD_L */
2520 mr_wr_addr |= 1<<7; /* A7 1 = Enable(Training Mode) */
2521 mr_wr_addr |= range<<6; /* A6 VrefDQ Training Range */
2522 mr_wr_addr |= value<<0; /* A5:A0 VrefDQ Training Value */
2523
2524 lmc_mr_mpr_ctl.s.mr_wr_addr = mr_wr_addr;
2525 lmc_mr_mpr_ctl.s.mr_wr_sel = 6; /* Write MR6 */
2526 lmc_mr_mpr_ctl.s.mr_wr_rank = rank;
2527 //lmc_mr_mpr_ctl.s.mr_wr_pda_mask =
2528 //lmc_mr_mpr_ctl.s.mr_wr_pda_enable =
2529 //lmc_mr_mpr_ctl.s.mpr_loc = location;
2530 //lmc_mr_mpr_ctl.s.mpr_wr = 0; /* Read=0, Write=1 */
2531 //lmc_mr_mpr_ctl.s.mpr_bit_select =
2532 //lmc_mr_mpr_ctl.s.mpr_byte_select =
2533 //lmc_mr_mpr_ctl.s.mpr_whole_byte_enable =
2534 //lmc_mr_mpr_ctl.s.mr_wr_use_default_value =
2535 //lmc_mr_mpr_ctl.s.mr_wr_bg1 =
2536 DRAM_CSR_WRITE(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num), lmc_mr_mpr_ctl.u);
2537
2538 /* 0x8 = Mode Register Write */
2539 perform_octeon3_ddr3_sequence(node, 1<<rank, ddr_interface_num, 0x8);
2540
2541 /* It is vendor specific whether Vref_value is captured with A7=1.
2542 A subsequent MRS might be necessary. */
2543 perform_octeon3_ddr3_sequence(node, 1<<rank, ddr_interface_num, 0x8);
2544
2545 mr_wr_addr &= ~(1<<7); /* A7 0 = Disable(Training Mode) */
2546 lmc_mr_mpr_ctl.s.mr_wr_addr = mr_wr_addr;
2547 DRAM_CSR_WRITE(node, BDK_LMCX_MR_MPR_CTL(ddr_interface_num), lmc_mr_mpr_ctl.u);
2548}
2549
2550static void set_DRAM_output_inversion (bdk_node_t node,
2551 int ddr_interface_num,
2552 int dimm_count,
2553 int rank_mask,
2554 int inversion)
2555{
2556 bdk_lmcx_ddr4_dimm_ctl_t lmc_ddr4_dimm_ctl;
2557 bdk_lmcx_dimmx_params_t lmc_dimmx_params;
2558 bdk_lmcx_dimm_ctl_t lmc_dimm_ctl;
2559 int dimm_no;
2560
2561 lmc_ddr4_dimm_ctl.u = 0; /* Don't touch extended register control words */
2562 DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), lmc_ddr4_dimm_ctl.u);
2563
2564 ddr_print("All DIMMs: Register Control Word RC0 : %x\n", (inversion & 1));
2565
2566 for (dimm_no = 0; dimm_no < dimm_count; ++dimm_no) {
2567 lmc_dimmx_params.u = BDK_CSR_READ(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm_no));
2568 lmc_dimmx_params.s.rc0 = (lmc_dimmx_params.s.rc0 & ~1) | (inversion & 1);
2569 DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm_no), lmc_dimmx_params.u);
2570 }
2571
2572 /* LMC0_DIMM_CTL */
2573 lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
2574 lmc_dimm_ctl.s.dimm0_wmask = 0x1;
2575 lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0x0001 : 0x0000;
2576
David Hendricks7d48ac52018-03-09 14:30:38 -08002577 ddr_print("LMC DIMM_CTL : 0x%016llx\n",
David Hendricks2004b932018-03-09 13:58:27 -08002578 lmc_dimm_ctl.u);
2579 DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
2580
2581 perform_octeon3_ddr3_sequence(node, rank_mask, ddr_interface_num, 0x7 ); /* Init RCW */
2582}
2583
2584static void write_mpr_page0_pattern (bdk_node_t node, int rank_mask,
2585 int ddr_interface_num, int dimm_count, int pattern, int location_mask)
2586{
2587 int rankx;
2588 int location;
2589
2590 for (rankx = 0; rankx < dimm_count*4; rankx++) {
2591 if (!(rank_mask & (1 << rankx)))
2592 continue;
2593 for (location = 0; location < 4; ++location) {
2594 if (!(location_mask & (1 << location)))
2595 continue;
2596
2597 ddr4_mpr_write(node, ddr_interface_num, rankx,
2598 /* page */ 0, /* location */ location, pattern);
2599 }
2600 }
2601}
2602
2603static void change_rdimm_mpr_pattern (bdk_node_t node, int rank_mask,
2604 int ddr_interface_num, int dimm_count)
2605{
2606 int save_ref_zqcs_int;
2607 bdk_lmcx_config_t lmc_config;
2608
2609 /*
2610 Okay, here is the latest sequence. This should work for all
2611 chips and passes (78,88,73,etc). This sequence should be run
2612 immediately after DRAM INIT. The basic idea is to write the
2613 same pattern into each of the 4 MPR locations in the DRAM, so
2614 that the same value is returned when doing MPR reads regardless
2615 of the inversion state. My advice is to put this into a
2616 function, change_rdimm_mpr_pattern or something like that, so
2617 that it can be called multiple times, as I think David wants a
2618 clock-like pattern for OFFSET training, but does not want a
2619 clock pattern for Bit-Deskew. You should then be able to call
2620 this at any point in the init sequence (after DRAM init) to
2621 change the pattern to a new value.
2622 Mike
2623
2624 A correction: PHY doesn't need any pattern during offset
2625 training, but needs clock like pattern for internal vref and
2626 bit-dskew training. So for that reason, these steps below have
2627 to be conducted before those trainings to pre-condition
2628 the pattern. David
2629
2630 Note: Step 3, 4, 8 and 9 have to be done through RDIMM
2631 sequence. If you issue MRW sequence to do RCW write (in o78 pass
2632 1 at least), LMC will still do two commands because
2633 CONTROL[RDIMM_ENA] is still set high. We don't want it to have
2634 any unintentional mode register write so it's best to do what
2635 Mike is doing here.
2636 Andrew
2637 */
2638
2639
2640 /* 1) Disable refresh (REF_ZQCS_INT = 0) */
2641
2642 debug_print("1) Disable refresh (REF_ZQCS_INT = 0)\n");
2643
2644 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
2645 save_ref_zqcs_int = lmc_config.s.ref_zqcs_int;
2646 lmc_config.s.ref_zqcs_int = 0;
2647 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
2648
2649
2650 /* 2) Put all devices in MPR mode (Run MRW sequence (sequence=8)
2651 with MODEREG_PARAMS0[MPRLOC]=0,
2652 MODEREG_PARAMS0[MPR]=1, MR_MPR_CTL[MR_WR_SEL]=3, and
2653 MR_MPR_CTL[MR_WR_USE_DEFAULT_VALUE]=1) */
2654
2655 debug_print("2) Put all devices in MPR mode (Run MRW sequence (sequence=8)\n");
2656
2657 set_mpr_mode(node, rank_mask, ddr_interface_num, dimm_count, /* mpr */ 1, /* bg1 */ 0); /* A-side */
2658 set_mpr_mode(node, rank_mask, ddr_interface_num, dimm_count, /* mpr */ 1, /* bg1 */ 1); /* B-side */
2659
2660 /* a. Or you can set MR_MPR_CTL[MR_WR_USE_DEFAULT_VALUE]=0 and set
2661 the value you would like directly into
2662 MR_MPR_CTL[MR_WR_ADDR] */
2663
2664 /* 3) Disable RCD Parity (if previously enabled) - parity does not
2665 work if inversion disabled */
2666
2667 debug_print("3) Disable RCD Parity\n");
2668
2669 /* 4) Disable Inversion in the RCD. */
2670 /* a. I did (3&4) via the RDIMM sequence (seq_sel=7), but it
2671 may be easier to use the MRW sequence (seq_sel=8). Just set
2672 MR_MPR_CTL[MR_WR_SEL]=7, MR_MPR_CTL[MR_WR_ADDR][3:0]=data,
2673 MR_MPR_CTL[MR_WR_ADDR][7:4]=RCD reg */
2674
2675 debug_print("4) Disable Inversion in the RCD.\n");
2676
2677 set_DRAM_output_inversion(node, ddr_interface_num, dimm_count, rank_mask,
2678 1 /* 1=disable output inversion*/);
2679
2680 /* 5) Disable CONTROL[RDIMM_ENA] so that MR sequence goes out
2681 non-inverted. */
2682
2683 debug_print("5) Disable CONTROL[RDIMM_ENA]\n");
2684
2685 set_rdimm_mode(node, ddr_interface_num, 0);
2686
2687 /* 6) Write all 4 MPR registers with the desired pattern (have to
2688 do this for all enabled ranks) */
2689 /* a. MR_MPR_CTL.MPR_WR=1, MR_MPR_CTL.MPR_LOC=0..3,
2690 MR_MPR_CTL.MR_WR_SEL=0, MR_MPR_CTL.MR_WR_ADDR[7:0]=pattern */
2691
2692 debug_print("6) Write all 4 MPR page 0 Training Patterns\n");
2693
2694 write_mpr_page0_pattern(node, rank_mask,
2695 ddr_interface_num, dimm_count, 0x55, 0x8);
2696
2697 /* 7) Re-enable RDIMM_ENA */
2698
2699 debug_print("7) Re-enable RDIMM_ENA\n");
2700
2701 set_rdimm_mode(node, ddr_interface_num, 1);
2702
2703 /* 8) Re-enable RDIMM inversion */
2704
2705 debug_print("8) Re-enable RDIMM inversion\n");
2706
2707 set_DRAM_output_inversion(node, ddr_interface_num, dimm_count, rank_mask,
2708 0 /* 0=re-enable output inversion*/);
2709
2710 /* 9) Re-enable RDIMM parity (if desired) */
2711
2712 debug_print("9) Re-enable RDIMM parity (if desired)\n");
2713
2714 /* 10)Take B-side devices out of MPR mode (Run MRW sequence
2715 (sequence=8) with MODEREG_PARAMS0[MPRLOC]=0,
2716 MODEREG_PARAMS0[MPR]=0, MR_MPR_CTL[MR_WR_SEL]=3, and
2717 MR_MPR_CTL[MR_WR_USE_DEFAULT_VALUE]=1) */
2718
2719 debug_print("10)Take B-side devices out of MPR mode\n");
2720
2721 set_mpr_mode(node, rank_mask, ddr_interface_num, dimm_count, /* mpr */ 0, /* bg1 */ 1);
2722
2723 /* a. Or you can set MR_MPR_CTL[MR_WR_USE_DEFAULT_VALUE]=0 and
2724 set the value you would like directly into
2725 MR_MPR_CTL[MR_WR_ADDR] */
2726
2727 /* 11)Re-enable refresh (REF_ZQCS_INT=previous value) */
2728
2729 debug_print("11)Re-enable refresh (REF_ZQCS_INT=previous value)\n");
2730
2731 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
2732 lmc_config.s.ref_zqcs_int = save_ref_zqcs_int;
2733 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
2734
2735}
2736
2737static unsigned char ddr4_rodt_ohms [RODT_OHMS_COUNT ] = { 0, 40, 60, 80, 120, 240, 34, 48 };
2738static unsigned char ddr4_rtt_nom_ohms [RTT_NOM_OHMS_COUNT ] = { 0, 60, 120, 40, 240, 48, 80, 34 };
2739static unsigned char ddr4_rtt_nom_table [RTT_NOM_TABLE_COUNT ] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2740static unsigned char ddr4_rtt_wr_ohms [RTT_WR_OHMS_COUNT ] = { 0, 120, 240, 99, 80 }; // setting HiZ ohms to 99 for computed vref
2741static unsigned char ddr4_dic_ohms [DIC_OHMS_COUNT ] = { 34, 48 };
2742static short ddr4_drive_strength[DRIVE_STRENGTH_COUNT] = { 0, 0, 26, 30, 34, 40, 48, 68, 0,0,0,0,0,0,0 };
2743static short ddr4_dqx_strength [DRIVE_STRENGTH_COUNT] = { 0, 24, 27, 30, 34, 40, 48, 60, 0,0,0,0,0,0,0 };
2744
2745impedence_values_t ddr4_impedence_values = {
2746 .rodt_ohms = ddr4_rodt_ohms ,
2747 .rtt_nom_ohms = ddr4_rtt_nom_ohms ,
2748 .rtt_nom_table = ddr4_rtt_nom_table ,
2749 .rtt_wr_ohms = ddr4_rtt_wr_ohms ,
2750 .dic_ohms = ddr4_dic_ohms ,
2751 .drive_strength = ddr4_drive_strength,
2752 .dqx_strength = ddr4_dqx_strength ,
2753};
2754
2755static unsigned char ddr3_rodt_ohms [RODT_OHMS_COUNT ] = { 0, 20, 30, 40, 60, 120, 0, 0 };
2756static unsigned char ddr3_rtt_nom_ohms [RTT_NOM_OHMS_COUNT ] = { 0, 60, 120, 40, 20, 30, 0, 0 };
2757static unsigned char ddr3_rtt_nom_table [RTT_NOM_TABLE_COUNT ] = { 0, 2, 1, 3, 5, 4, 0, 0 };
2758static unsigned char ddr3_rtt_wr_ohms [RTT_WR_OHMS_COUNT ] = { 0, 60, 120 };
2759static unsigned char ddr3_dic_ohms [DIC_OHMS_COUNT ] = { 40, 34 };
2760static short ddr3_drive_strength[DRIVE_STRENGTH_COUNT] = { 0, 24, 27, 30, 34, 40, 48, 60, 0,0,0,0,0,0,0 };
2761static impedence_values_t ddr3_impedence_values = {
2762 .rodt_ohms = ddr3_rodt_ohms ,
2763 .rtt_nom_ohms = ddr3_rtt_nom_ohms ,
2764 .rtt_nom_table = ddr3_rtt_nom_table ,
2765 .rtt_wr_ohms = ddr3_rtt_wr_ohms ,
2766 .dic_ohms = ddr3_dic_ohms ,
2767 .drive_strength = ddr3_drive_strength,
2768 .dqx_strength = ddr3_drive_strength,
2769};
2770
2771
2772uint64_t
2773hertz_to_psecs(uint64_t hertz)
2774{
2775 return divide_nint((uint64_t) 1000*1000*1000*1000, hertz); /* Clock in psecs */
2776}
2777
2778#define DIVIDEND_SCALE 1000 /* Scale to avoid rounding error. */
2779uint64_t
2780psecs_to_mts(uint64_t psecs)
2781{
2782 //ddr_print("psecs %ld, divisor %ld\n", psecs, divide_nint((uint64_t)(2 * 1000000 * DIVIDEND_SCALE), psecs));
2783 return divide_nint(divide_nint((uint64_t)(2 * 1000000 * DIVIDEND_SCALE), psecs), DIVIDEND_SCALE);
2784}
2785
2786#define WITHIN(v,b,m) (((v)>=((b)-(m)))&&((v)<=((b)+(m))))
2787
2788// pretty-print version, only works with what comes from the SPD: tCKmin or tCKAVGmin
2789unsigned long
2790pretty_psecs_to_mts(uint64_t psecs)
2791{
2792 uint64_t ret = 0; // default to error
2793 if (WITHIN(psecs, 1250, 1))
2794 ret = 1600;
2795 else if (WITHIN(psecs, 1071, 1))
2796 ret = 1866;
2797 else if (WITHIN(psecs, 937, 1))
2798 ret = 2133;
2799 else if (WITHIN(psecs, 833, 1))
2800 ret = 2400;
2801 else if (WITHIN(psecs, 750, 1))
2802 ret = 2666;
2803 return ret;
2804}
2805
2806uint64_t
2807mts_to_hertz(uint64_t mts)
2808{
2809 return ((mts * 1000 * 1000) / 2);
2810}
2811
2812#define DEBUG_RC3X_COMPUTE 0
2813#define rc3x_print(...) \
2814 do { if (DEBUG_RC3X_COMPUTE) printf(__VA_ARGS__); } while (0)
2815
2816static int compute_rc3x (int64_t tclk_psecs)
2817{
2818 long speed;
2819 long tclk_psecs_min, tclk_psecs_max;
2820 long data_rate_mhz, data_rate_mhz_min, data_rate_mhz_max;
2821 int rc3x;
2822
2823#define ENCODING_BASE 1240
2824
2825 data_rate_mhz = psecs_to_mts(tclk_psecs);
2826
2827 /* 2400 MT/s is a special case. Using integer arithmetic it rounds
2828 from 833 psecs to 2401 MT/s. Force it to 2400 to pick the
2829 proper setting from the table. */
2830 if (tclk_psecs == 833)
2831 data_rate_mhz = 2400;
2832
2833 for (speed = ENCODING_BASE; speed < 3200; speed += 20) {
2834 int error = 0;
2835
2836 tclk_psecs_min = hertz_to_psecs(mts_to_hertz(speed + 00)); /* Clock in psecs */
2837 tclk_psecs_max = hertz_to_psecs(mts_to_hertz(speed + 18)); /* Clock in psecs */
2838
2839 data_rate_mhz_min = psecs_to_mts(tclk_psecs_min);
2840 data_rate_mhz_max = psecs_to_mts(tclk_psecs_max);
2841
2842 /* Force alingment to multiple to avound rounding errors. */
2843 data_rate_mhz_min = ((data_rate_mhz_min + 18) / 20) * 20;
2844 data_rate_mhz_max = ((data_rate_mhz_max + 18) / 20) * 20;
2845
2846 error += (speed + 00 != data_rate_mhz_min);
2847 error += (speed + 20 != data_rate_mhz_max);
2848
2849 rc3x = (speed - ENCODING_BASE) / 20;
2850
2851 rc3x_print("rc3x: %02x speed: %4ld MT/s < f <= %4ld MT/s, psec: %3ld:%3ld %4ld:%4ld %s\n",
2852 rc3x,
2853 speed, speed + 20,
2854 tclk_psecs_min, tclk_psecs_max,
2855 data_rate_mhz_min, data_rate_mhz_max,
2856 error ? "****" : "");
2857
2858 if (data_rate_mhz <= (speed + 20)) {
2859 rc3x_print("rc3x: %4ld MT/s <= %4ld MT/s\n", data_rate_mhz, speed + 20);
2860 break;
2861 }
2862 }
2863 return rc3x;
2864}
2865
2866static const int rlevel_separate_ab = 1;
2867
2868int init_octeon3_ddr3_interface(bdk_node_t node,
2869 const ddr_configuration_t *ddr_configuration,
2870 uint32_t ddr_hertz,
2871 uint32_t cpu_hertz,
2872 uint32_t ddr_ref_hertz,
2873 int board_type,
2874 int board_rev_maj,
2875 int board_rev_min,
2876 int ddr_interface_num,
2877 uint32_t ddr_interface_mask
2878 )
2879{
2880 const char *s;
2881
2882 const dimm_odt_config_t *odt_1rank_config = ddr_configuration->odt_1rank_config;
2883 const dimm_odt_config_t *odt_2rank_config = ddr_configuration->odt_2rank_config;
2884 const dimm_odt_config_t *odt_4rank_config = ddr_configuration->odt_4rank_config;
2885 const dimm_config_t *dimm_config_table = ddr_configuration->dimm_config_table;
2886 const dimm_odt_config_t *odt_config;
2887 const ddr3_custom_config_t *custom_lmc_config = &ddr_configuration->custom_lmc_config;
2888 int odt_idx;
2889
2890 /*
2891 ** Compute clock rates to the nearest picosecond.
2892 */
2893 uint64_t tclk_psecs = hertz_to_psecs(ddr_hertz); /* Clock in psecs */
2894 uint64_t eclk_psecs = hertz_to_psecs(cpu_hertz); /* Clock in psecs */
2895
2896 int row_bits, col_bits, num_banks, num_ranks, dram_width;
2897 int dimm_count = 0;
2898 int fatal_error = 0; /* Accumulate and report all the errors before giving up */
2899
2900 int safe_ddr_flag = 0; /* Flag that indicates safe DDR settings should be used */
2901 int ddr_interface_64b = 1; /* THUNDER Default: 64bit interface width */
2902 int ddr_interface_bytemask;
2903 uint32_t mem_size_mbytes = 0;
2904 unsigned int didx;
2905 int bank_bits = 0;
2906 int bunk_enable;
2907 int rank_mask;
2908 int column_bits_start = 1;
2909 int row_lsb;
2910 int pbank_lsb;
2911 int use_ecc = 1;
2912 int mtb_psec = 0; /* quiet */
2913 short ftb_Dividend;
2914 short ftb_Divisor;
2915 int tAAmin;
2916 int tCKmin;
2917 int CL, min_cas_latency = 0, max_cas_latency = 0, override_cas_latency = 0;
2918 int ddr_rtt_nom_auto, ddr_rodt_ctl_auto;
2919 int i;
2920
2921 int spd_addr;
2922 int spd_org;
2923 int spd_banks;
2924 int spd_rdimm;
2925 int spd_dimm_type;
2926 int spd_ecc;
2927 uint32_t spd_cas_latency;
2928 int spd_mtb_dividend;
2929 int spd_mtb_divisor;
2930 int spd_tck_min;
2931 int spd_taa_min;
2932 int spd_twr;
2933 int spd_trcd;
2934 int spd_trrd;
2935 int spd_trp;
2936 int spd_tras;
2937 int spd_trc;
2938 int spd_trfc;
2939 int spd_twtr;
2940 int spd_trtp;
2941 int spd_tfaw;
2942 int spd_addr_mirror;
2943 int spd_package = 0;
2944 int spd_rawcard = 0;
2945 int spd_rawcard_AorB = 0;
2946 int is_stacked_die = 0;
2947 int disable_stacked_die = 0;
2948 int is_3ds_dimm = 0; // 3DS
2949 int lranks_per_prank = 1; // 3DS: logical ranks per package rank
2950 int lranks_bits = 0; // 3DS: logical ranks bits
2951 int die_capacity = 0; // in Mbits; only used for 3DS
2952
2953 /* FTB values are two's complement ranging from +127 to -128. */
2954 typedef signed char SC_t;
2955
2956 int twr;
2957 int trcd;
2958 int trrd;
2959 int trp;
2960 int tras;
2961 int trc;
2962 int trfc;
2963 int twtr;
2964 int trtp = 0; /* quiet */
2965 int tfaw;
2966
2967 int wlevel_bitmask_errors = 0;
2968 int wlevel_loops;
2969 int default_rtt_nom[4];
2970 int dyn_rtt_nom_mask = 0;
2971
2972 ddr_type_t ddr_type;
2973 int ddr4_tCKAVGmin = 0; /* quiet */
2974 int ddr4_tCKAVGmax = 0; /* quiet */
2975 int ddr4_tRCDmin = 0; /* quiet */
2976 int ddr4_tRPmin = 0; /* quiet */
2977 int ddr4_tRASmin = 0; /* quiet */
2978 int ddr4_tRCmin = 0; /* quiet */
2979 int ddr4_tRFC1min = 0; /* quiet */
2980 int ddr4_tRFC2min = 0; /* quiet */
2981 int ddr4_tRFC4min = 0; /* quiet */
2982 int ddr4_tFAWmin = 0; /* quiet */
2983 int ddr4_tRRD_Smin = 0; /* quiet */
2984 int ddr4_tRRD_Lmin;
2985 int ddr4_tCCD_Lmin;
2986 impedence_values_t *imp_values;
2987 int default_rodt_ctl;
2988 // default to disabled (ie, LMC restart, not chip reset)
2989 int ddr_disable_chip_reset = 1;
2990 int disable_deskew_training = 0;
2991 const char *dimm_type_name;
2992
2993 /* Allow the Write bit-deskew feature to be enabled when desired. */
2994 // NOTE: THUNDER pass 2.x only, 81xx, 83xx
2995 int enable_write_deskew = ENABLE_WRITE_DESKEW_DEFAULT;
2996
2997#if SWL_TRY_HWL_ALT
2998 typedef struct {
David Hendricks7d48ac52018-03-09 14:30:38 -08002999 uint16_t hwl_alt_mask; // mask of bytelanes with alternate
3000 uint16_t hwl_alt_delay[9]; // bytelane alternate avail if mask=1
David Hendricks2004b932018-03-09 13:58:27 -08003001 } hwl_alt_by_rank_t;
3002 hwl_alt_by_rank_t hwl_alts[4];
3003 memset(hwl_alts, 0, sizeof(hwl_alts));
3004#endif /* SWL_TRY_HWL_ALT */
3005
3006 bdk_lmcx_config_t lmc_config;
3007
3008 /* Initialize these to shut up the compiler. They are configured
3009 and used only for DDR4 */
3010 ddr4_tRRD_Lmin = 6000;
3011 ddr4_tCCD_Lmin = 6000;
3012
3013 ddr_print("\nInitializing node %d DDR interface %d, DDR Clock %d, DDR Reference Clock %d\n",
3014 node, ddr_interface_num, ddr_hertz, ddr_ref_hertz);
3015
3016 if (dimm_config_table[0].spd_addr == 0 && !dimm_config_table[0].spd_ptr) {
3017 error_print("ERROR: No dimms specified in the dimm_config_table.\n");
3018 return (-1);
3019 }
3020
3021 // allow some overrides to be done
3022
3023 // this one controls whether chip RESET is done, or LMC init restarted from step 6.9.6
3024 if ((s = lookup_env_parameter("ddr_disable_chip_reset")) != NULL) {
3025 ddr_disable_chip_reset = !!strtoul(s, NULL, 0);
3026 }
3027 // this one controls whether Deskew Training is performed
3028 if ((s = lookup_env_parameter("ddr_disable_deskew_training")) != NULL) {
3029 disable_deskew_training = !!strtoul(s, NULL, 0);
3030 }
3031 // this one is in Validate_Read_Deskew_Training and controls a preliminary delay
3032 if ((s = lookup_env_parameter("ddr_deskew_validation_delay")) != NULL) {
3033 deskew_validation_delay = strtoul(s, NULL, 0);
3034 }
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003035 // this one is in Perform_Read_Deskew_Training and controls lock retries
David Hendricks2004b932018-03-09 13:58:27 -08003036 if ((s = lookup_env_parameter("ddr_lock_retries")) != NULL) {
3037 default_lock_retry_limit = strtoul(s, NULL, 0);
3038 }
3039 // this one controls whether stacked die status can affect processing
3040 // disabling it will affect computed vref adjustment, and rodt_row_skip_mask
3041 if ((s = lookup_env_parameter("ddr_disable_stacked_die")) != NULL) {
3042 disable_stacked_die = !!strtoul(s, NULL, 0);
3043 }
3044
3045 // setup/override for write bit-deskew feature
3046 if (! CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
3047 // FIXME: allow override
3048 if ((s = lookup_env_parameter("ddr_enable_write_deskew")) != NULL) {
3049 enable_write_deskew = !!strtoul(s, NULL, 0);
3050 } // else take default setting
3051 } else { // not pass 2.x
3052 enable_write_deskew = 0; // force disabled
3053 }
3054
3055#if 0 // FIXME: do we really need this anymore?
3056 if (dram_is_verbose(VBL_NORM)) {
3057 printf("DDR SPD Table:");
3058 for (didx = 0; didx < DDR_CFG_T_MAX_DIMMS; ++didx) {
3059 if (dimm_config_table[didx].spd_addr == 0) break;
3060 printf(" --ddr%dspd=0x%02x", ddr_interface_num, dimm_config_table[didx].spd_addr);
3061 }
3062 printf("\n");
3063 }
3064#endif
3065
3066 /*
3067 ** Walk the DRAM Socket Configuration Table to see what is installed.
3068 */
3069 for (didx = 0; didx < DDR_CFG_T_MAX_DIMMS; ++didx)
3070 {
3071 /* Check for lower DIMM socket populated */
3072 if (validate_dimm(node, &dimm_config_table[didx]) == 1) {
3073 // NOTE: DIMM info printing is now done later when more details are available
3074 ++dimm_count;
3075 } else { break; } /* Finished when there is no lower DIMM */
3076 }
3077
3078
3079 initialize_ddr_clock(node,
David Hendricks7d48ac52018-03-09 14:30:38 -08003080 ddr_configuration,
3081 cpu_hertz,
3082 ddr_hertz,
3083 ddr_ref_hertz,
3084 ddr_interface_num,
3085 ddr_interface_mask);
David Hendricks2004b932018-03-09 13:58:27 -08003086
3087 if (!odt_1rank_config)
3088 odt_1rank_config = disable_odt_config;
3089 if (!odt_2rank_config)
3090 odt_2rank_config = disable_odt_config;
3091 if (!odt_4rank_config)
3092 odt_4rank_config = disable_odt_config;
3093
3094 if ((s = lookup_env_parameter("ddr_safe")) != NULL) {
3095 safe_ddr_flag = !!strtoul(s, NULL, 0);
3096 }
3097
3098
3099 if (dimm_count == 0) {
3100 error_print("ERROR: DIMM 0 not detected.\n");
3101 return(-1);
3102 }
3103
3104 // look for 32-bit mode specified in the config
3105 if (custom_lmc_config->mode32b) {
3106 ddr_interface_64b = 0;
3107 }
3108
3109 if (ddr_interface_64b == 0) { // check if 32-bit mode is bad
3110 if (!CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
3111 error_print("32-bit interface width is NOT supported for this Thunder model\n");
3112 ddr_interface_64b = 1; // force to 64-bit
3113 }
3114 } else { // check if 64-bit mode is bad
3115 if (CAVIUM_IS_MODEL(CAVIUM_CN81XX)) { // check the fuses on 81XX for forced 32-bit mode
3116 BDK_CSR_INIT(mio_fus_dat2, node, BDK_MIO_FUS_DAT2);
3117 if (mio_fus_dat2.s.lmc_mode32) {
3118 error_print("32-bit interface width is ONLY supported for this Thunder model\n");
3119 ddr_interface_64b = 0; // force to 32-bit
3120 }
3121 }
3122 }
3123
3124 // finally, say we are in 32-bit mode when it has been validated
3125 if (ddr_interface_64b == 0) {
3126 ddr_print("N%d.LMC%d: Setting 32-bit data width\n",
3127 node, ddr_interface_num);
3128 }
3129
3130 /* ddr_type only indicates DDR4 or DDR3 */
3131 ddr_type = get_ddr_type(node, &dimm_config_table[0]);
3132 debug_print("DRAM Device Type: DDR%d\n", ddr_type);
3133
3134 spd_dimm_type = get_dimm_module_type(node, &dimm_config_table[0], ddr_type);
3135
3136 if (ddr_type == DDR4_DRAM) {
3137 int spd_module_type;
3138 int asymmetric;
3139 const char *signal_load[4] = {"", "MLS", "3DS", "RSV"};
3140
3141 imp_values = &ddr4_impedence_values;
3142 dimm_type_name = ddr4_dimm_types[spd_dimm_type];
3143
3144 spd_addr = read_spd(node, &dimm_config_table[0], DDR4_SPD_ADDRESSING_ROW_COL_BITS);
3145 spd_org = read_spd(node, &dimm_config_table[0], DDR4_SPD_MODULE_ORGANIZATION);
3146 spd_banks = 0xFF & read_spd(node, &dimm_config_table[0], DDR4_SPD_DENSITY_BANKS);
3147
3148 bank_bits = (2 + ((spd_banks >> 4) & 0x3)) + ((spd_banks >> 6) & 0x3);
3149 bank_bits = min((int)bank_bits, 4); /* Controller can only address 4 bits. */
3150
Subrata Banik8e6d5f22020-08-30 13:51:44 +05303151 spd_package = 0xFF & read_spd(node, &dimm_config_table[0], DDR4_SPD_PACKAGE_TYPE);
David Hendricks2004b932018-03-09 13:58:27 -08003152 if (spd_package & 0x80) { // non-monolithic device
3153 is_stacked_die = (!disable_stacked_die) ? ((spd_package & 0x73) == 0x11) : 0;
3154 ddr_print("DDR4: Package Type 0x%x (%s), %d die\n", spd_package,
3155 signal_load[(spd_package & 3)], ((spd_package >> 4) & 7) + 1);
3156 is_3ds_dimm = ((spd_package & 3) == 2); // is it 3DS?
3157 if (is_3ds_dimm) { // is it 3DS?
3158 lranks_per_prank = ((spd_package >> 4) & 7) + 1;
3159 // FIXME: should make sure it is only 2H or 4H or 8H?
3160 lranks_bits = lranks_per_prank >> 1;
3161 if (lranks_bits == 4) lranks_bits = 3;
3162 }
3163 } else if (spd_package != 0) {
3164 // FIXME: print non-zero monolithic device definition
3165 ddr_print("DDR4: Package Type MONOLITHIC: %d die, signal load %d\n",
3166 ((spd_package >> 4) & 7) + 1, (spd_package & 3));
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003167 }
David Hendricks2004b932018-03-09 13:58:27 -08003168
3169 asymmetric = (spd_org >> 6) & 1;
3170 if (asymmetric) {
3171 int spd_secondary_pkg = read_spd(node, &dimm_config_table[0],
3172 DDR4_SPD_SECONDARY_PACKAGE_TYPE);
3173 ddr_print("DDR4: Module Organization: ASYMMETRICAL: Secondary Package Type 0x%x\n",
3174 spd_secondary_pkg);
3175 } else {
3176 uint64_t bus_width = 8 << (0x07 & read_spd(node, &dimm_config_table[0],
3177 DDR4_SPD_MODULE_MEMORY_BUS_WIDTH));
3178 uint64_t ddr_width = 4 << ((spd_org >> 0) & 0x7);
3179 uint64_t module_cap;
3180 int shift = (spd_banks & 0x0F);
3181 die_capacity = (shift < 8) ? (256UL << shift) : ((12UL << (shift & 1)) << 10);
3182 ddr_print("DDR4: Module Organization: SYMMETRICAL: capacity per die %d %cbit\n",
3183 (die_capacity > 512) ? (die_capacity >> 10) : die_capacity,
3184 (die_capacity > 512) ? 'G' : 'M');
3185 module_cap = ((uint64_t)die_capacity << 20) / 8UL * bus_width / ddr_width *
3186 /* no. pkg ranks*/(1UL + ((spd_org >> 3) & 0x7));
3187 if (is_3ds_dimm) // is it 3DS?
3188 module_cap *= /* die_count */(uint64_t)(((spd_package >> 4) & 7) + 1);
David Hendricks7d48ac52018-03-09 14:30:38 -08003189 ddr_print("DDR4: Module Organization: SYMMETRICAL: capacity per module %lld GB\n",
David Hendricks2004b932018-03-09 13:58:27 -08003190 module_cap >> 30);
3191 }
3192
3193 spd_rawcard = 0xFF & read_spd(node, &dimm_config_table[0], DDR4_SPD_REFERENCE_RAW_CARD);
3194 ddr_print("DDR4: Reference Raw Card 0x%x \n", spd_rawcard);
3195
3196 spd_module_type = read_spd(node, &dimm_config_table[0], DDR4_SPD_KEY_BYTE_MODULE_TYPE);
3197 if (spd_module_type & 0x80) { // HYBRID module
3198 ddr_print("DDR4: HYBRID module, type %s\n",
3199 ((spd_module_type & 0x70) == 0x10) ? "NVDIMM" : "UNKNOWN");
3200 }
3201
3202 spd_dimm_type = spd_module_type & 0x0F;
3203 spd_rdimm = (spd_dimm_type == 1) || (spd_dimm_type == 5) || (spd_dimm_type == 8);
David Hendricks7d48ac52018-03-09 14:30:38 -08003204 if (spd_rdimm) {
3205 int spd_mfgr_id = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_LSB) |
3206 (read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_MANUFACTURER_ID_MSB) << 8);
3207 int spd_register_rev = read_spd(node, &dimm_config_table[0], DDR4_SPD_REGISTER_REVISION_NUMBER);
3208 ddr_print("DDR4: RDIMM Register Manufacturer ID 0x%x Revision 0x%x\n",
3209 spd_mfgr_id, spd_register_rev);
David Hendricks2004b932018-03-09 13:58:27 -08003210
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003211 // RAWCARD A or B must be bit 7=0 and bits 4-0 either 00000(A) or 00001(B)
David Hendricks7d48ac52018-03-09 14:30:38 -08003212 spd_rawcard_AorB = ((spd_rawcard & 0x9fUL) <= 1);
3213 }
David Hendricks2004b932018-03-09 13:58:27 -08003214 } else {
3215 imp_values = &ddr3_impedence_values;
3216 dimm_type_name = ddr3_dimm_types[spd_dimm_type];
3217
3218 spd_addr = read_spd(node, &dimm_config_table[0], DDR3_SPD_ADDRESSING_ROW_COL_BITS);
3219 spd_org = read_spd(node, &dimm_config_table[0], DDR3_SPD_MODULE_ORGANIZATION);
3220 spd_banks = read_spd(node, &dimm_config_table[0], DDR3_SPD_DENSITY_BANKS) & 0xff;
3221
3222 bank_bits = 3 + ((spd_banks >> 4) & 0x7);
3223 bank_bits = min((int)bank_bits, 3); /* Controller can only address 3 bits. */
3224
3225 spd_rdimm = (spd_dimm_type == 1) || (spd_dimm_type == 5) || (spd_dimm_type == 9);
3226 }
3227
3228#if 0 // FIXME: why should this be possible OR needed?
3229 if ((s = lookup_env_parameter("ddr_rdimm_ena")) != NULL) {
3230 spd_rdimm = !!strtoul(s, NULL, 0);
3231 }
3232#endif
3233
3234 debug_print("spd_addr : %#06x\n", spd_addr );
3235 debug_print("spd_org : %#06x\n", spd_org );
3236 debug_print("spd_banks : %#06x\n", spd_banks );
3237
3238 row_bits = 12 + ((spd_addr >> 3) & 0x7);
3239 col_bits = 9 + ((spd_addr >> 0) & 0x7);
3240
3241 num_ranks = 1 + ((spd_org >> 3) & 0x7);
3242 dram_width = 4 << ((spd_org >> 0) & 0x7);
3243 num_banks = 1 << bank_bits;
3244
3245 if ((s = lookup_env_parameter("ddr_num_ranks")) != NULL) {
3246 num_ranks = strtoul(s, NULL, 0);
3247 }
3248
3249 /* FIX
3250 ** Check that values are within some theoretical limits.
3251 ** col_bits(min) = row_lsb(min) - bank_bits(max) - bus_bits(max) = 14 - 3 - 4 = 7
3252 ** col_bits(max) = row_lsb(max) - bank_bits(min) - bus_bits(min) = 18 - 2 - 3 = 13
3253 */
3254 if ((col_bits > 13) || (col_bits < 7)) {
3255 error_print("Unsupported number of Col Bits: %d\n", col_bits);
3256 ++fatal_error;
3257 }
3258
3259 /* FIX
3260 ** Check that values are within some theoretical limits.
3261 ** row_bits(min) = pbank_lsb(min) - row_lsb(max) - rank_bits = 26 - 18 - 1 = 7
3262 ** row_bits(max) = pbank_lsb(max) - row_lsb(min) - rank_bits = 33 - 14 - 1 = 18
3263 */
3264 if ((row_bits > 18) || (row_bits < 7)) {
3265 error_print("Unsupported number of Row Bits: %d\n", row_bits);
3266 ++fatal_error;
3267 }
3268
David Hendricks7d48ac52018-03-09 14:30:38 -08003269 wlevel_loops = WLEVEL_LOOPS_DEFAULT;
3270 // accept generic or interface-specific override but not for ASIM...
3271 if ((s = lookup_env_parameter("ddr_wlevel_loops")) == NULL)
3272 s = lookup_env_parameter("ddr%d_wlevel_loops", ddr_interface_num);
3273 if (s != NULL) {
3274 wlevel_loops = strtoul(s, NULL, 0);
3275 }
David Hendricks2004b932018-03-09 13:58:27 -08003276
3277 bunk_enable = (num_ranks > 1);
3278
3279 column_bits_start = 3;
3280
3281 row_lsb = column_bits_start + col_bits + bank_bits - (! ddr_interface_64b);
3282 debug_print("row_lsb = column_bits_start + col_bits + bank_bits = %d\n", row_lsb);
3283
3284 pbank_lsb = row_lsb + row_bits + bunk_enable;
3285 debug_print("pbank_lsb = row_lsb + row_bits + bunk_enable = %d\n", pbank_lsb);
3286
3287 if (lranks_per_prank > 1) {
3288 pbank_lsb = row_lsb + row_bits + lranks_bits + bunk_enable;
3289 ddr_print("DDR4: 3DS: pbank_lsb = (%d row_lsb) + (%d row_bits) + (%d lranks_bits) + (%d bunk_enable) = %d\n",
3290 row_lsb, row_bits, lranks_bits, bunk_enable, pbank_lsb);
3291 }
3292
3293 mem_size_mbytes = dimm_count * ((1ull << pbank_lsb) >> 20);
3294 if (num_ranks == 4) {
3295 /* Quad rank dimm capacity is equivalent to two dual-rank dimms. */
3296 mem_size_mbytes *= 2;
3297 }
3298
Peter Lemenkov5797b2e2018-10-19 16:57:27 +02003299 /* Mask with 1 bits set for each active rank, allowing 2 bits per dimm.
David Hendricks2004b932018-03-09 13:58:27 -08003300 ** This makes later calculations simpler, as a variety of CSRs use this layout.
3301 ** This init needs to be updated for dual configs (ie non-identical DIMMs).
3302 ** Bit 0 = dimm0, rank 0
3303 ** Bit 1 = dimm0, rank 1
3304 ** Bit 2 = dimm1, rank 0
3305 ** Bit 3 = dimm1, rank 1
3306 ** ...
3307 */
3308 rank_mask = 0x1;
3309 if (num_ranks > 1)
3310 rank_mask = 0x3;
3311 if (num_ranks > 2)
3312 rank_mask = 0xf;
3313
3314 for (i = 1; i < dimm_count; i++)
3315 rank_mask |= ((rank_mask & 0x3) << (2*i));
3316
3317
3318#ifdef CAVIUM_ONLY
3319 /* Special request: mismatched DIMM support. Slot 0: 2-Rank, Slot 1: 1-Rank */
3320 if (0)
3321 {
3322 /*
3323 ** Calculate the total memory size in terms of the total
3324 ** number of ranks instead of the number of dimms. The usual
3325 ** requirement is for both dimms to be identical. This check
3326 ** works around that requirement to allow one exception. The
3327 ** dimm in the second slot may now have fewer ranks than the
3328 ** first slot.
3329 */
3330 int spd_org_dimm1;
3331 int num_ranks_dimm1;
3332 int rank_count;
3333 int rank_mask_dimm1;
3334
3335 if (dimm_count > 1) {
3336 spd_org_dimm1 = read_spd(node, &dimm_config_table[1] /* dimm 1*/,
3337 DDR3_SPD_MODULE_ORGANIZATION);
3338 num_ranks_dimm1 = 1 + ((spd_org_dimm1 >> 3) & 0x7);
3339 rank_count = num_ranks/* dimm 0 */ + num_ranks_dimm1 /* dimm 1 */;
3340
3341 if (num_ranks != num_ranks_dimm1) {
3342 mem_size_mbytes = rank_count * ((1ull << (pbank_lsb-bunk_enable)) >> 20);
3343 rank_mask = 1 | ((num_ranks > 1) << 1);
3344 rank_mask_dimm1 = 1 | ((num_ranks_dimm1 > 1) << 1);
3345 rank_mask |= ((rank_mask_dimm1 & 0x3) << 2);
3346 ddr_print("DIMM 1 - ranks: %d, size: %d MB\n",
3347 num_ranks_dimm1, num_ranks_dimm1 * ((1ull << (pbank_lsb-bunk_enable)) >> 20));
3348 }
3349 }
3350 }
3351#endif /* CAVIUM_ONLY */
3352
3353 spd_ecc = get_dimm_ecc(node, &dimm_config_table[0], ddr_type);
3354
3355 VB_PRT(VBL_DEV, "Summary: - %d %s%s %dRx%d %s, row bits=%d, col bits=%d, bank bits=%d\n",
3356 dimm_count, dimm_type_name, (dimm_count > 1) ? "s" : "",
3357 num_ranks, dram_width, (spd_ecc) ? "ECC" : "non-ECC",
3358 row_bits, col_bits, bank_bits);
3359
3360 // always print out the useful DIMM information...
3361 for (i = 0; i < DDR_CFG_T_MAX_DIMMS; i++) {
3362 if (i < dimm_count)
3363 report_dimm(node, &dimm_config_table[i], i, ddr_interface_num,
3364 num_ranks, dram_width, mem_size_mbytes / dimm_count);
3365 else
3366 if (validate_dimm(node, &dimm_config_table[i]) == 0) // only if there is a slot
3367 printf("N%d.LMC%d.DIMM%d: Not Present\n", node, ddr_interface_num, i);
3368 }
3369
3370 if (ddr_type == DDR4_DRAM) {
David Hendricks7d48ac52018-03-09 14:30:38 -08003371 spd_cas_latency = ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE0)) << 0);
3372 spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE1)) << 8);
3373 spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE2)) << 16);
3374 spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR4_SPD_CAS_LATENCIES_BYTE3)) << 24);
David Hendricks2004b932018-03-09 13:58:27 -08003375 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08003376 spd_cas_latency = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_LSB);
3377 spd_cas_latency |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_CAS_LATENCIES_MSB)) << 8);
David Hendricks2004b932018-03-09 13:58:27 -08003378 }
3379 debug_print("spd_cas_latency : %#06x\n", spd_cas_latency );
3380
3381 if (ddr_type == DDR4_DRAM) {
3382
3383 /* No other values for DDR4 MTB and FTB are specified at the
3384 * current time so don't bother reading them. Can't speculate how
3385 * new values will be represented.
3386 */
3387 int spdMTB = 125;
3388 int spdFTB = 1;
3389
3390 tAAmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003391 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_TAAMIN)
3392 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_LATENCY_FINE_TAAMIN);
David Hendricks2004b932018-03-09 13:58:27 -08003393
3394 ddr4_tCKAVGmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003395 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MINIMUM_CYCLE_TIME_TCKAVGMIN)
3396 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CYCLE_TIME_FINE_TCKAVGMIN);
David Hendricks2004b932018-03-09 13:58:27 -08003397
3398 ddr4_tCKAVGmax
David Hendricks7d48ac52018-03-09 14:30:38 -08003399 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MAXIMUM_CYCLE_TIME_TCKAVGMAX)
3400 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MAX_CYCLE_TIME_FINE_TCKAVGMAX);
David Hendricks2004b932018-03-09 13:58:27 -08003401
3402 ddr4_tRCDmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003403 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_CAS_DELAY_TRCDMIN)
3404 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_RAS_TO_CAS_DELAY_FINE_TRCDMIN);
David Hendricks2004b932018-03-09 13:58:27 -08003405
3406 ddr4_tRPmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003407 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_TRPMIN)
3408 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_PRECHARGE_DELAY_FINE_TRPMIN);
David Hendricks2004b932018-03-09 13:58:27 -08003409
3410 ddr4_tRASmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003411 = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) & 0xf) << 8) +
3412 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_PRECHARGE_LSB_TRASMIN) & 0xff));
David Hendricks2004b932018-03-09 13:58:27 -08003413
3414 ddr4_tRCmin
David Hendricks7d48ac52018-03-09 14:30:38 -08003415 = spdMTB * ((((read_spd(node, &dimm_config_table[0], DDR4_SPD_UPPER_NIBBLES_TRAS_TRC) >> 4) & 0xf) << 8) +
3416 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACTIVE_REFRESH_LSB_TRCMIN) & 0xff))
3417 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACT_TO_ACT_REFRESH_DELAY_FINE_TRCMIN);
David Hendricks2004b932018-03-09 13:58:27 -08003418
3419 ddr4_tRFC1min
David Hendricks7d48ac52018-03-09 14:30:38 -08003420 = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC1MIN) & 0xff) << 8) +
3421 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_LSB_TRFC1MIN) & 0xff));
David Hendricks2004b932018-03-09 13:58:27 -08003422
3423 ddr4_tRFC2min
3424 = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC2MIN) & 0xff) << 8) +
3425 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_LSB_TRFC2MIN) & 0xff));
3426
3427 ddr4_tRFC4min
3428 = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_MSB_TRFC4MIN) & 0xff) << 8) +
3429 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_REFRESH_RECOVERY_LSB_TRFC4MIN) & 0xff));
3430
3431 ddr4_tFAWmin
3432 = spdMTB * (((read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_FOUR_ACTIVE_WINDOW_MSN_TFAWMIN) & 0xf) << 8) +
3433 ( read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_FOUR_ACTIVE_WINDOW_LSB_TFAWMIN) & 0xff));
3434
3435 ddr4_tRRD_Smin
3436 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_ACTIVE_DELAY_SAME_TRRD_SMIN)
3437 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACT_TO_ACT_DELAY_DIFF_FINE_TRRD_SMIN);
3438
3439 ddr4_tRRD_Lmin
3440 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ROW_ACTIVE_DELAY_DIFF_TRRD_LMIN)
3441 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_ACT_TO_ACT_DELAY_SAME_FINE_TRRD_LMIN);
3442
3443 ddr4_tCCD_Lmin
3444 = spdMTB * read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_TO_CAS_DELAY_TCCD_LMIN)
3445 + spdFTB * (SC_t) read_spd(node, &dimm_config_table[0], DDR4_SPD_MIN_CAS_TO_CAS_DELAY_FINE_TCCD_LMIN);
3446
David Hendricks7d48ac52018-03-09 14:30:38 -08003447 ddr_print("%-45s : %6d ps\n", "Medium Timebase (MTB)", spdMTB);
3448 ddr_print("%-45s : %6d ps\n", "Fine Timebase (FTB)", spdFTB);
David Hendricks2004b932018-03-09 13:58:27 -08003449
3450 #define DDR4_TWR 15000
3451 #define DDR4_TWTR_S 2500
3452
3453
David Hendricks7d48ac52018-03-09 14:30:38 -08003454 tCKmin = ddr4_tCKAVGmin;
David Hendricks2004b932018-03-09 13:58:27 -08003455 twr = DDR4_TWR;
3456 trcd = ddr4_tRCDmin;
3457 trrd = ddr4_tRRD_Smin;
3458 trp = ddr4_tRPmin;
3459 tras = ddr4_tRASmin;
3460 trc = ddr4_tRCmin;
3461 trfc = ddr4_tRFC1min;
3462 twtr = DDR4_TWTR_S;
3463 tfaw = ddr4_tFAWmin;
3464
3465 if (spd_rdimm) {
David Hendricks7d48ac52018-03-09 14:30:38 -08003466 spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_RDIMM_ADDR_MAPPING_FROM_REGISTER_TO_DRAM) & 0x1;
David Hendricks2004b932018-03-09 13:58:27 -08003467 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08003468 spd_addr_mirror = read_spd(node, &dimm_config_table[0], DDR4_SPD_UDIMM_ADDR_MAPPING_FROM_EDGE) & 0x1;
David Hendricks2004b932018-03-09 13:58:27 -08003469 }
3470 debug_print("spd_addr_mirror : %#06x\n", spd_addr_mirror );
3471
3472 } else { /* if (ddr_type == DDR4_DRAM) */
3473 spd_mtb_dividend = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MEDIUM_TIMEBASE_DIVIDEND);
3474 spd_mtb_divisor = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MEDIUM_TIMEBASE_DIVISOR);
3475 spd_tck_min = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MINIMUM_CYCLE_TIME_TCKMIN);
3476 spd_taa_min = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_CAS_LATENCY_TAAMIN);
3477
3478 spd_twr = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_WRITE_RECOVERY_TWRMIN);
3479 spd_trcd = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_RAS_CAS_DELAY_TRCDMIN);
3480 spd_trrd = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_ROW_ACTIVE_DELAY_TRRDMIN);
3481 spd_trp = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_ROW_PRECHARGE_DELAY_TRPMIN);
3482 spd_tras = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_ACTIVE_PRECHARGE_LSB_TRASMIN);
3483 spd_tras |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_UPPER_NIBBLES_TRAS_TRC)&0xf) << 8);
3484 spd_trc = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_ACTIVE_REFRESH_LSB_TRCMIN);
3485 spd_trc |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_UPPER_NIBBLES_TRAS_TRC)&0xf0) << 4);
3486 spd_trfc = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_REFRESH_RECOVERY_LSB_TRFCMIN);
3487 spd_trfc |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_REFRESH_RECOVERY_MSB_TRFCMIN)) << 8);
3488 spd_twtr = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_INTERNAL_WRITE_READ_CMD_TWTRMIN);
3489 spd_trtp = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_INTERNAL_READ_PRECHARGE_CMD_TRTPMIN);
3490 spd_tfaw = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_FOUR_ACTIVE_WINDOW_TFAWMIN);
3491 spd_tfaw |= ((0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_UPPER_NIBBLE_TFAW)&0xf) << 8);
3492 spd_addr_mirror = 0xff & read_spd(node, &dimm_config_table[0], DDR3_SPD_ADDRESS_MAPPING) & 0x1;
3493 spd_addr_mirror = spd_addr_mirror && !spd_rdimm; /* Only address mirror unbuffered dimms. */
3494 ftb_Dividend = read_spd(node, &dimm_config_table[0], DDR3_SPD_FINE_TIMEBASE_DIVIDEND_DIVISOR) >> 4;
3495 ftb_Divisor = read_spd(node, &dimm_config_table[0], DDR3_SPD_FINE_TIMEBASE_DIVIDEND_DIVISOR) & 0xf;
3496 ftb_Divisor = (ftb_Divisor == 0) ? 1 : ftb_Divisor; /* Make sure that it is not 0 */
3497
3498 debug_print("spd_twr : %#06x\n", spd_twr );
3499 debug_print("spd_trcd : %#06x\n", spd_trcd);
3500 debug_print("spd_trrd : %#06x\n", spd_trrd);
3501 debug_print("spd_trp : %#06x\n", spd_trp );
3502 debug_print("spd_tras : %#06x\n", spd_tras);
3503 debug_print("spd_trc : %#06x\n", spd_trc );
3504 debug_print("spd_trfc : %#06x\n", spd_trfc);
3505 debug_print("spd_twtr : %#06x\n", spd_twtr);
3506 debug_print("spd_trtp : %#06x\n", spd_trtp);
3507 debug_print("spd_tfaw : %#06x\n", spd_tfaw);
3508 debug_print("spd_addr_mirror : %#06x\n", spd_addr_mirror);
3509
3510 mtb_psec = spd_mtb_dividend * 1000 / spd_mtb_divisor;
3511 tAAmin = mtb_psec * spd_taa_min;
3512 tAAmin += ftb_Dividend * (SC_t) read_spd(node, &dimm_config_table[0], DDR3_SPD_MIN_CAS_LATENCY_FINE_TAAMIN) / ftb_Divisor;
3513 tCKmin = mtb_psec * spd_tck_min;
3514 tCKmin += ftb_Dividend * (SC_t) read_spd(node, &dimm_config_table[0], DDR3_SPD_MINIMUM_CYCLE_TIME_FINE_TCKMIN) / ftb_Divisor;
3515
3516 twr = spd_twr * mtb_psec;
3517 trcd = spd_trcd * mtb_psec;
3518 trrd = spd_trrd * mtb_psec;
3519 trp = spd_trp * mtb_psec;
3520 tras = spd_tras * mtb_psec;
3521 trc = spd_trc * mtb_psec;
3522 trfc = spd_trfc * mtb_psec;
3523 twtr = spd_twtr * mtb_psec;
3524 trtp = spd_trtp * mtb_psec;
3525 tfaw = spd_tfaw * mtb_psec;
3526
3527 } /* if (ddr_type == DDR4_DRAM) */
3528
3529 if (ddr_type == DDR4_DRAM) {
3530 ddr_print("%-45s : %6d ps (%ld MT/s)\n", "SDRAM Minimum Cycle Time (tCKAVGmin)",ddr4_tCKAVGmin,
3531 pretty_psecs_to_mts(ddr4_tCKAVGmin));
3532 ddr_print("%-45s : %6d ps\n", "SDRAM Maximum Cycle Time (tCKAVGmax)", ddr4_tCKAVGmax);
3533 ddr_print("%-45s : %6d ps\n", "Minimum CAS Latency Time (tAAmin)", tAAmin);
3534 ddr_print("%-45s : %6d ps\n", "Minimum RAS to CAS Delay Time (tRCDmin)", ddr4_tRCDmin);
3535 ddr_print("%-45s : %6d ps\n", "Minimum Row Precharge Delay Time (tRPmin)", ddr4_tRPmin);
3536 ddr_print("%-45s : %6d ps\n", "Minimum Active to Precharge Delay (tRASmin)", ddr4_tRASmin);
3537 ddr_print("%-45s : %6d ps\n", "Minimum Active to Active/Refr. Delay (tRCmin)", ddr4_tRCmin);
3538 ddr_print("%-45s : %6d ps\n", "Minimum Refresh Recovery Delay (tRFC1min)", ddr4_tRFC1min);
3539 ddr_print("%-45s : %6d ps\n", "Minimum Refresh Recovery Delay (tRFC2min)", ddr4_tRFC2min);
3540 ddr_print("%-45s : %6d ps\n", "Minimum Refresh Recovery Delay (tRFC4min)", ddr4_tRFC4min);
3541 ddr_print("%-45s : %6d ps\n", "Minimum Four Activate Window Time (tFAWmin)", ddr4_tFAWmin);
3542 ddr_print("%-45s : %6d ps\n", "Minimum Act. to Act. Delay (tRRD_Smin)", ddr4_tRRD_Smin);
3543 ddr_print("%-45s : %6d ps\n", "Minimum Act. to Act. Delay (tRRD_Lmin)", ddr4_tRRD_Lmin);
3544 ddr_print("%-45s : %6d ps\n", "Minimum CAS to CAS Delay Time (tCCD_Lmin)", ddr4_tCCD_Lmin);
3545 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08003546 ddr_print("Medium Timebase (MTB) : %6d ps\n", mtb_psec);
3547 ddr_print("Minimum Cycle Time (tCKmin) : %6d ps (%ld MT/s)\n", tCKmin,
David Hendricks2004b932018-03-09 13:58:27 -08003548 pretty_psecs_to_mts(tCKmin));
David Hendricks7d48ac52018-03-09 14:30:38 -08003549 ddr_print("Minimum CAS Latency Time (tAAmin) : %6d ps\n", tAAmin);
3550 ddr_print("Write Recovery Time (tWR) : %6d ps\n", twr);
3551 ddr_print("Minimum RAS to CAS delay (tRCD) : %6d ps\n", trcd);
3552 ddr_print("Minimum Row Active to Row Active delay (tRRD) : %6d ps\n", trrd);
3553 ddr_print("Minimum Row Precharge Delay (tRP) : %6d ps\n", trp);
3554 ddr_print("Minimum Active to Precharge (tRAS) : %6d ps\n", tras);
3555 ddr_print("Minimum Active to Active/Refresh Delay (tRC) : %6d ps\n", trc);
3556 ddr_print("Minimum Refresh Recovery Delay (tRFC) : %6d ps\n", trfc);
3557 ddr_print("Internal write to read command delay (tWTR) : %6d ps\n", twtr);
3558 ddr_print("Min Internal Rd to Precharge Cmd Delay (tRTP) : %6d ps\n", trtp);
3559 ddr_print("Minimum Four Activate Window Delay (tFAW) : %6d ps\n", tfaw);
David Hendricks2004b932018-03-09 13:58:27 -08003560 }
3561
3562
3563 /* When the cycle time is within 1 psec of the minimum accept it
3564 as a slight rounding error and adjust it to exactly the minimum
3565 cycle time. This avoids an unnecessary warning. */
3566 if (_abs(tclk_psecs - tCKmin) < 2)
3567 tclk_psecs = tCKmin;
3568
3569 if (tclk_psecs < (uint64_t)tCKmin) {
David Hendricks7d48ac52018-03-09 14:30:38 -08003570 ddr_print("WARNING!!!!: DDR Clock Rate (tCLK: %lld) exceeds DIMM specifications (tCKmin: %lld)!!!!\n",
David Hendricks2004b932018-03-09 13:58:27 -08003571 tclk_psecs, (uint64_t)tCKmin);
3572 }
3573
3574
David Hendricks7d48ac52018-03-09 14:30:38 -08003575 ddr_print("DDR Clock Rate (tCLK) : %6llu ps\n", tclk_psecs);
3576 ddr_print("Core Clock Rate (eCLK) : %6llu ps\n", eclk_psecs);
David Hendricks2004b932018-03-09 13:58:27 -08003577
3578 if ((s = lookup_env_parameter("ddr_use_ecc")) != NULL) {
3579 use_ecc = !!strtoul(s, NULL, 0);
3580 }
3581 use_ecc = use_ecc && spd_ecc;
3582
3583 ddr_interface_bytemask = ddr_interface_64b
3584 ? (use_ecc ? 0x1ff : 0xff)
3585 : (use_ecc ? 0x01f : 0x0f); // FIXME? 81xx does diff from 70xx
3586
3587 ddr_print("DRAM Interface width: %d bits %s bytemask 0x%x\n",
3588 ddr_interface_64b ? 64 : 32, use_ecc ? "+ECC" : "",
3589 ddr_interface_bytemask);
3590
3591 ddr_print("\n------ Board Custom Configuration Settings ------\n");
3592 ddr_print("%-45s : %d\n", "MIN_RTT_NOM_IDX ", custom_lmc_config->min_rtt_nom_idx);
3593 ddr_print("%-45s : %d\n", "MAX_RTT_NOM_IDX ", custom_lmc_config->max_rtt_nom_idx);
3594 ddr_print("%-45s : %d\n", "MIN_RODT_CTL ", custom_lmc_config->min_rodt_ctl);
3595 ddr_print("%-45s : %d\n", "MAX_RODT_CTL ", custom_lmc_config->max_rodt_ctl);
3596 ddr_print("%-45s : %d\n", "MIN_CAS_LATENCY ", custom_lmc_config->min_cas_latency);
3597 ddr_print("%-45s : %d\n", "OFFSET_EN ", custom_lmc_config->offset_en);
3598 ddr_print("%-45s : %d\n", "OFFSET_UDIMM ", custom_lmc_config->offset_udimm);
3599 ddr_print("%-45s : %d\n", "OFFSET_RDIMM ", custom_lmc_config->offset_rdimm);
3600 ddr_print("%-45s : %d\n", "DDR_RTT_NOM_AUTO ", custom_lmc_config->ddr_rtt_nom_auto);
3601 ddr_print("%-45s : %d\n", "DDR_RODT_CTL_AUTO ", custom_lmc_config->ddr_rodt_ctl_auto);
3602 if (spd_rdimm)
3603 ddr_print("%-45s : %d\n", "RLEVEL_COMP_OFFSET", custom_lmc_config->rlevel_comp_offset_rdimm);
3604 else
3605 ddr_print("%-45s : %d\n", "RLEVEL_COMP_OFFSET", custom_lmc_config->rlevel_comp_offset_udimm);
3606 ddr_print("%-45s : %d\n", "RLEVEL_COMPUTE ", custom_lmc_config->rlevel_compute);
3607 ddr_print("%-45s : %d\n", "DDR2T_UDIMM ", custom_lmc_config->ddr2t_udimm);
3608 ddr_print("%-45s : %d\n", "DDR2T_RDIMM ", custom_lmc_config->ddr2t_rdimm);
3609 ddr_print("%-45s : %d\n", "FPRCH2 ", custom_lmc_config->fprch2);
3610 ddr_print("-------------------------------------------------\n");
3611
3612
3613 CL = divide_roundup(tAAmin, tclk_psecs);
3614
3615 ddr_print("Desired CAS Latency : %6d\n", CL);
3616
3617 min_cas_latency = custom_lmc_config->min_cas_latency;
3618
3619
3620 if ((s = lookup_env_parameter("ddr_min_cas_latency")) != NULL) {
3621 min_cas_latency = strtoul(s, NULL, 0);
3622 }
3623
3624 {
3625 int base_CL;
3626 ddr_print("CAS Latencies supported in DIMM :");
3627 base_CL = (ddr_type == DDR4_DRAM) ? 7 : 4;
3628 for (i=0; i<32; ++i) {
3629 if ((spd_cas_latency >> i) & 1) {
3630 ddr_print(" %d", i+base_CL);
3631 max_cas_latency = i+base_CL;
3632 if (min_cas_latency == 0)
3633 min_cas_latency = i+base_CL;
3634 }
3635 }
3636 ddr_print("\n");
3637
3638 /* Use relaxed timing when running slower than the minimum
3639 supported speed. Adjust timing to match the smallest supported
3640 CAS Latency. */
3641 if (CL < min_cas_latency) {
3642 uint64_t adjusted_tclk = tAAmin / min_cas_latency;
3643 CL = min_cas_latency;
David Hendricks7d48ac52018-03-09 14:30:38 -08003644 ddr_print("Slow clock speed. Adjusting timing: tClk = %llu, Adjusted tClk = %lld\n",
David Hendricks2004b932018-03-09 13:58:27 -08003645 tclk_psecs, adjusted_tclk);
3646 tclk_psecs = adjusted_tclk;
3647 }
3648
3649 if ((s = lookup_env_parameter("ddr_cas_latency")) != NULL) {
3650 override_cas_latency = strtoul(s, NULL, 0);
3651 }
3652
3653 /* Make sure that the selected cas latency is legal */
3654 for (i=(CL-base_CL); i<32; ++i) {
3655 if ((spd_cas_latency >> i) & 1) {
3656 CL = i+base_CL;
3657 break;
3658 }
3659 }
3660 }
3661
3662 if (CL > max_cas_latency)
3663 CL = max_cas_latency;
3664
3665 if (override_cas_latency != 0) {
3666 CL = override_cas_latency;
3667 }
3668
3669 ddr_print("CAS Latency : %6d\n", CL);
3670
3671 if ((CL * tCKmin) > 20000)
3672 {
3673 ddr_print("(CLactual * tCKmin) = %d exceeds 20 ns\n", (CL * tCKmin));
3674 }
3675
3676 if ((num_banks != 4) && (num_banks != 8) && (num_banks != 16))
3677 {
3678 error_print("Unsupported number of banks %d. Must be 4 or 8 or 16.\n", num_banks);
3679 ++fatal_error;
3680 }
3681
3682 if ((num_ranks != 1) && (num_ranks != 2) && (num_ranks != 4))
3683 {
3684 error_print("Unsupported number of ranks: %d\n", num_ranks);
3685 ++fatal_error;
3686 }
3687
3688 if (! CAVIUM_IS_MODEL(CAVIUM_CN81XX)) { // 88XX or 83XX, but not 81XX
3689 if ((dram_width != 8) && (dram_width != 16) && (dram_width != 4)) {
3690 error_print("Unsupported SDRAM Width, x%d. Must be x4, x8 or x16.\n", dram_width);
3691 ++fatal_error;
3692 }
3693 } else if ((dram_width != 8) && (dram_width != 16)) { // 81XX can only do x8 or x16
3694 error_print("Unsupported SDRAM Width, x%d. Must be x8 or x16.\n", dram_width);
3695 ++fatal_error;
3696 }
3697
3698
3699 /*
3700 ** Bail out here if things are not copasetic.
3701 */
3702 if (fatal_error)
3703 return(-1);
3704
3705 /*
3706 * 6.9.6 LMC RESET Initialization
3707 *
3708 * The purpose of this step is to assert/deassert the RESET# pin at the
3709 * DDR3/DDR4 parts.
3710 *
3711 * This LMC RESET step is done for all enabled LMCs.
3712 */
3713 perform_lmc_reset(node, ddr_interface_num);
3714
3715 // Make sure scrambling is disabled during init...
3716 {
3717 bdk_lmcx_control_t lmc_control;
3718
3719 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
3720 lmc_control.s.scramble_ena = 0;
3721 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
3722
3723 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG0(ddr_interface_num), 0);
3724 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG1(ddr_interface_num), 0);
3725 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG2(ddr_interface_num), 0);
3726 }
3727
3728
3729 odt_idx = dimm_count - 1;
3730
3731 switch (num_ranks) {
3732 case 1:
3733 odt_config = odt_1rank_config;
3734 break;
3735 case 2:
3736 odt_config = odt_2rank_config;
3737 break;
3738 case 4:
3739 odt_config = odt_4rank_config;
3740 break;
3741 default:
3742 odt_config = disable_odt_config;
3743 error_print("Unsupported number of ranks: %d\n", num_ranks);
3744 ++fatal_error;
3745 }
3746
3747
3748 /* Parameters from DDR3 Specifications */
3749#define DDR3_tREFI 7800000 /* 7.8 us */
3750#define DDR3_ZQCS 80000ull /* 80 ns */
3751#define DDR3_ZQCS_Interval 1280000000 /* 128ms/100 */
3752#define DDR3_tCKE 5000 /* 5 ns */
3753#define DDR3_tMRD 4 /* 4 nCK */
3754#define DDR3_tDLLK 512 /* 512 nCK */
3755#define DDR3_tMPRR 1 /* 1 nCK */
3756#define DDR3_tWLMRD 40 /* 40 nCK */
3757#define DDR3_tWLDQSEN 25 /* 25 nCK */
3758
3759 /* Parameters from DDR4 Specifications */
3760#define DDR4_tMRD 8 /* 8 nCK */
3761#define DDR4_tDLLK 768 /* 768 nCK */
3762
3763 /*
3764 * 6.9.7 Early LMC Initialization
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003765 *
David Hendricks2004b932018-03-09 13:58:27 -08003766 * All of DDR PLL, LMC CK, and LMC DRESET initializations must be
3767 * completed prior to starting this LMC initialization sequence.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003768 *
David Hendricks2004b932018-03-09 13:58:27 -08003769 * Perform the following five substeps for early LMC initialization:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003770 *
David Hendricks2004b932018-03-09 13:58:27 -08003771 * 1. Software must ensure there are no pending DRAM transactions.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01003772 *
David Hendricks2004b932018-03-09 13:58:27 -08003773 * 2. Write LMC(0)_CONFIG, LMC(0)_CONTROL, LMC(0)_TIMING_PARAMS0,
3774 * LMC(0)_TIMING_PARAMS1, LMC(0)_MODEREG_PARAMS0,
3775 * LMC(0)_MODEREG_PARAMS1, LMC(0)_DUAL_MEMCFG, LMC(0)_NXM,
3776 * LMC(0)_WODT_MASK, LMC(0)_RODT_MASK, LMC(0)_COMP_CTL2,
3777 * LMC(0)_PHY_CTL, LMC(0)_DIMM0/1_PARAMS, and LMC(0)_DIMM_CTL with
3778 * appropriate values. All sections in this chapter can be used to
3779 * derive proper register settings.
3780 */
3781
3782 /* LMC(0)_CONFIG */
3783 {
3784 lmc_config.u = 0;
3785
3786 lmc_config.s.ecc_ena = use_ecc;
3787 lmc_config.s.row_lsb = encode_row_lsb_ddr3(row_lsb, ddr_interface_64b);
3788 lmc_config.s.pbank_lsb = encode_pbank_lsb_ddr3(pbank_lsb, ddr_interface_64b);
3789
3790 lmc_config.s.idlepower = 0; /* Disabled */
3791
3792 if ((s = lookup_env_parameter("ddr_idlepower")) != NULL) {
3793 lmc_config.s.idlepower = strtoul(s, NULL, 0);
3794 }
3795
3796 lmc_config.s.forcewrite = 0; /* Disabled */
3797 lmc_config.s.ecc_adr = 1; /* Include memory reference address in the ECC */
3798
3799 if ((s = lookup_env_parameter("ddr_ecc_adr")) != NULL) {
3800 lmc_config.s.ecc_adr = strtoul(s, NULL, 0);
3801 }
3802
3803 lmc_config.s.reset = 0;
3804
3805 /*
3806 * Program LMC0_CONFIG[24:18], ref_zqcs_int(6:0) to
3807 * RND-DN(tREFI/clkPeriod/512) Program LMC0_CONFIG[36:25],
3808 * ref_zqcs_int(18:7) to
3809 * RND-DN(ZQCS_Interval/clkPeriod/(512*128)). Note that this
3810 * value should always be greater than 32, to account for
3811 * resistor calibration delays.
3812 */
3813
3814 lmc_config.s.ref_zqcs_int = ((DDR3_tREFI/tclk_psecs/512) & 0x7f);
3815 lmc_config.s.ref_zqcs_int |= ((max(33ull, (DDR3_ZQCS_Interval/(tclk_psecs/100)/(512*128))) & 0xfff) << 7);
3816
3817
3818 lmc_config.s.early_dqx = 1; /* Default to enabled */
3819
3820 if ((s = lookup_env_parameter("ddr_early_dqx")) == NULL)
3821 s = lookup_env_parameter("ddr%d_early_dqx", ddr_interface_num);
3822 if (s != NULL) {
3823 lmc_config.s.early_dqx = strtoul(s, NULL, 0);
3824 }
3825
3826 lmc_config.s.sref_with_dll = 0;
3827
3828 lmc_config.s.rank_ena = bunk_enable;
3829 lmc_config.s.rankmask = rank_mask; /* Set later */
3830 lmc_config.s.mirrmask = (spd_addr_mirror << 1 | spd_addr_mirror << 3) & rank_mask;
3831 lmc_config.s.init_status = rank_mask; /* Set once and don't change it. */
3832 lmc_config.s.early_unload_d0_r0 = 0;
3833 lmc_config.s.early_unload_d0_r1 = 0;
3834 lmc_config.s.early_unload_d1_r0 = 0;
3835 lmc_config.s.early_unload_d1_r1 = 0;
3836 lmc_config.s.scrz = 0;
3837 // set 32-bit mode for real only when selected AND 81xx...
3838 if (!ddr_interface_64b && CAVIUM_IS_MODEL(CAVIUM_CN81XX)) {
3839 lmc_config.s.mode32b = 1;
3840 }
3841 VB_PRT(VBL_DEV, "%-45s : %d\n", "MODE32B (init)", lmc_config.s.mode32b);
3842 lmc_config.s.mode_x4dev = (dram_width == 4) ? 1 : 0;
David Hendricks7d48ac52018-03-09 14:30:38 -08003843 lmc_config.s.bg2_enable = ((ddr_type == DDR4_DRAM) && (dram_width == 16)) ? 0 : 1;
David Hendricks2004b932018-03-09 13:58:27 -08003844
3845 if ((s = lookup_env_parameter_ull("ddr_config")) != NULL) {
3846 lmc_config.u = strtoull(s, NULL, 0);
3847 }
David Hendricks7d48ac52018-03-09 14:30:38 -08003848 ddr_print("LMC_CONFIG : 0x%016llx\n", lmc_config.u);
David Hendricks2004b932018-03-09 13:58:27 -08003849 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
3850 }
3851
3852 /* LMC(0)_CONTROL */
3853 {
3854 bdk_lmcx_control_t lmc_control;
3855 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
3856 lmc_control.s.rdimm_ena = spd_rdimm;
3857 lmc_control.s.bwcnt = 0; /* Clear counter later */
3858 if (spd_rdimm)
3859 lmc_control.s.ddr2t = (safe_ddr_flag ? 1 : custom_lmc_config->ddr2t_rdimm );
3860 else
3861 lmc_control.s.ddr2t = (safe_ddr_flag ? 1 : custom_lmc_config->ddr2t_udimm );
3862 lmc_control.s.pocas = 0;
3863 lmc_control.s.fprch2 = (safe_ddr_flag ? 2 : custom_lmc_config->fprch2 );
3864 lmc_control.s.throttle_rd = safe_ddr_flag ? 1 : 0;
3865 lmc_control.s.throttle_wr = safe_ddr_flag ? 1 : 0;
3866 lmc_control.s.inorder_rd = safe_ddr_flag ? 1 : 0;
3867 lmc_control.s.inorder_wr = safe_ddr_flag ? 1 : 0;
3868 lmc_control.cn81xx.elev_prio_dis = safe_ddr_flag ? 1 : 0;
3869 lmc_control.s.nxm_write_en = 0; /* discards writes to
3870 addresses that don't exist
3871 in the DRAM */
3872 lmc_control.s.max_write_batch = 8;
3873 lmc_control.s.xor_bank = 1;
3874 lmc_control.s.auto_dclkdis = 1;
3875 lmc_control.s.int_zqcs_dis = 0;
3876 lmc_control.s.ext_zqcs_dis = 0;
3877 lmc_control.s.bprch = 1;
3878 lmc_control.s.wodt_bprch = 1;
3879 lmc_control.s.rodt_bprch = 1;
3880
3881 if ((s = lookup_env_parameter("ddr_xor_bank")) != NULL) {
3882 lmc_control.s.xor_bank = strtoul(s, NULL, 0);
3883 }
3884
3885 if ((s = lookup_env_parameter("ddr_2t")) != NULL) {
3886 lmc_control.s.ddr2t = strtoul(s, NULL, 0);
3887 }
3888
3889 if ((s = lookup_env_parameter("ddr_fprch2")) != NULL) {
3890 lmc_control.s.fprch2 = strtoul(s, NULL, 0);
3891 }
3892
3893 if ((s = lookup_env_parameter("ddr_bprch")) != NULL) {
3894 lmc_control.s.bprch = strtoul(s, NULL, 0);
3895 }
3896
3897 if ((s = lookup_env_parameter("ddr_wodt_bprch")) != NULL) {
3898 lmc_control.s.wodt_bprch = strtoul(s, NULL, 0);
3899 }
3900
3901 if ((s = lookup_env_parameter("ddr_rodt_bprch")) != NULL) {
3902 lmc_control.s.rodt_bprch = strtoul(s, NULL, 0);
3903 }
3904
3905 if ((s = lookup_env_parameter("ddr_int_zqcs_dis")) != NULL) {
3906 lmc_control.s.int_zqcs_dis = strtoul(s, NULL, 0);
3907 }
3908
3909 if ((s = lookup_env_parameter("ddr_ext_zqcs_dis")) != NULL) {
3910 lmc_control.s.ext_zqcs_dis = strtoul(s, NULL, 0);
3911 }
3912
3913 if ((s = lookup_env_parameter_ull("ddr_control")) != NULL) {
3914 lmc_control.u = strtoull(s, NULL, 0);
3915 }
David Hendricks7d48ac52018-03-09 14:30:38 -08003916 ddr_print("LMC_CONTROL : 0x%016llx\n", lmc_control.u);
David Hendricks2004b932018-03-09 13:58:27 -08003917 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
3918 }
3919
3920 /* LMC(0)_TIMING_PARAMS0 */
3921 {
3922 unsigned trp_value;
3923 bdk_lmcx_timing_params0_t lmc_timing_params0;
3924 lmc_timing_params0.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS0(ddr_interface_num));
3925
3926 trp_value = divide_roundup(trp, tclk_psecs) - 1;
3927 ddr_print("TIMING_PARAMS0[TRP]: NEW 0x%x, OLD 0x%x\n", trp_value,
3928 trp_value + (unsigned)(divide_roundup(max(4*tclk_psecs, 7500ull), tclk_psecs)) - 4);
3929#if 1
3930 if ((s = lookup_env_parameter_ull("ddr_use_old_trp")) != NULL) {
3931 if (!!strtoull(s, NULL, 0)) {
3932 trp_value += divide_roundup(max(4*tclk_psecs, 7500ull), tclk_psecs) - 4;
3933 ddr_print("TIMING_PARAMS0[trp]: USING OLD 0x%x\n", trp_value);
3934 }
3935 }
3936#endif
3937
3938 lmc_timing_params0.s.txpr = divide_roundup(max(5*tclk_psecs, trfc+10000ull), 16*tclk_psecs);
3939 lmc_timing_params0.s.tzqinit = divide_roundup(max(512*tclk_psecs, 640000ull), (256*tclk_psecs));
3940 lmc_timing_params0.s.trp = trp_value & 0x1f;
3941 lmc_timing_params0.s.tcksre = divide_roundup(max(5*tclk_psecs, 10000ull), tclk_psecs) - 1;
3942
3943 if (ddr_type == DDR4_DRAM) {
3944 lmc_timing_params0.s.tzqcs = divide_roundup(128*tclk_psecs, (16*tclk_psecs)); /* Always 8. */
David Hendricks7d48ac52018-03-09 14:30:38 -08003945 lmc_timing_params0.s.tcke = divide_roundup(max(3*tclk_psecs, (uint64_t) DDR3_tCKE), tclk_psecs) - 1;
3946 lmc_timing_params0.s.tmrd = divide_roundup((DDR4_tMRD*tclk_psecs), tclk_psecs) - 1;
3947 //lmc_timing_params0.s.tmod = divide_roundup(max(24*tclk_psecs, 15000ull), tclk_psecs) - 1;
3948 lmc_timing_params0.s.tmod = 25; /* 25 is the max allowed */
3949 lmc_timing_params0.s.tdllk = divide_roundup(DDR4_tDLLK, 256);
David Hendricks2004b932018-03-09 13:58:27 -08003950 } else {
3951 lmc_timing_params0.s.tzqcs = divide_roundup(max(64*tclk_psecs, DDR3_ZQCS), (16*tclk_psecs));
David Hendricks7d48ac52018-03-09 14:30:38 -08003952 lmc_timing_params0.s.tcke = divide_roundup(DDR3_tCKE, tclk_psecs) - 1;
3953 lmc_timing_params0.s.tmrd = divide_roundup((DDR3_tMRD*tclk_psecs), tclk_psecs) - 1;
3954 lmc_timing_params0.s.tmod = divide_roundup(max(12*tclk_psecs, 15000ull), tclk_psecs) - 1;
3955 lmc_timing_params0.s.tdllk = divide_roundup(DDR3_tDLLK, 256);
David Hendricks2004b932018-03-09 13:58:27 -08003956 }
3957
3958 if ((s = lookup_env_parameter_ull("ddr_timing_params0")) != NULL) {
3959 lmc_timing_params0.u = strtoull(s, NULL, 0);
3960 }
David Hendricks7d48ac52018-03-09 14:30:38 -08003961 ddr_print("TIMING_PARAMS0 : 0x%016llx\n", lmc_timing_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08003962 DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS0(ddr_interface_num), lmc_timing_params0.u);
3963 }
3964
3965 /* LMC(0)_TIMING_PARAMS1 */
3966 {
3967 int txp, temp_trcd, trfc_dlr;
3968 bdk_lmcx_timing_params1_t lmc_timing_params1;
3969 lmc_timing_params1.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num));
3970
3971 lmc_timing_params1.s.tmprr = divide_roundup(DDR3_tMPRR*tclk_psecs, tclk_psecs) - 1;
3972
3973 lmc_timing_params1.s.tras = divide_roundup(tras, tclk_psecs) - 1;
3974
David Hendricks7d48ac52018-03-09 14:30:38 -08003975 // NOTE: this is reworked for pass 2.x
3976 temp_trcd = divide_roundup(trcd, tclk_psecs);
David Hendricks2004b932018-03-09 13:58:27 -08003977#if 1
3978 if (temp_trcd > 15)
3979 ddr_print("TIMING_PARAMS1[trcd]: need extension bit for 0x%x\n", temp_trcd);
3980#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08003981 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trcd > 15)) {
3982 /* Let .trcd=0 serve as a flag that the field has
3983 overflowed. Must use Additive Latency mode as a
3984 workaround. */
3985 temp_trcd = 0;
3986 }
3987 lmc_timing_params1.s.trcd = temp_trcd & 0x0f;
3988 lmc_timing_params1.s.trcd_ext = (temp_trcd >> 4) & 1;
David Hendricks2004b932018-03-09 13:58:27 -08003989
3990 lmc_timing_params1.s.twtr = divide_roundup(twtr, tclk_psecs) - 1;
3991 lmc_timing_params1.s.trfc = divide_roundup(trfc, 8*tclk_psecs);
3992
David Hendricks7d48ac52018-03-09 14:30:38 -08003993 // workaround needed for all THUNDER chips thru T88 Pass 2.0,
3994 // but not 81xx and 83xx...
David Hendricks2004b932018-03-09 13:58:27 -08003995 if ((ddr_type == DDR4_DRAM) && CAVIUM_IS_MODEL(CAVIUM_CN88XX)) {
3996 /* Workaround bug 24006. Use Trrd_l. */
3997 lmc_timing_params1.s.trrd = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 2;
3998 } else
3999 lmc_timing_params1.s.trrd = divide_roundup(trrd, tclk_psecs) - 2;
4000
4001 /*
4002 ** tXP = max( 3nCK, 7.5 ns) DDR3-800 tCLK = 2500 psec
4003 ** tXP = max( 3nCK, 7.5 ns) DDR3-1066 tCLK = 1875 psec
4004 ** tXP = max( 3nCK, 6.0 ns) DDR3-1333 tCLK = 1500 psec
4005 ** tXP = max( 3nCK, 6.0 ns) DDR3-1600 tCLK = 1250 psec
4006 ** tXP = max( 3nCK, 6.0 ns) DDR3-1866 tCLK = 1071 psec
4007 ** tXP = max( 3nCK, 6.0 ns) DDR3-2133 tCLK = 937 psec
4008 */
4009 txp = (tclk_psecs < 1875) ? 6000 : 7500;
David Hendricks7d48ac52018-03-09 14:30:38 -08004010 // NOTE: this is reworked for pass 2.x
4011 int temp_txp = divide_roundup(max(3*tclk_psecs, (unsigned)txp), tclk_psecs) - 1;
David Hendricks2004b932018-03-09 13:58:27 -08004012#if 1
4013 if (temp_txp > 7)
4014 ddr_print("TIMING_PARAMS1[txp]: need extension bit for 0x%x\n", temp_txp);
4015#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08004016 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_txp > 7)) {
4017 temp_txp = 7; // max it out
4018 }
4019 lmc_timing_params1.s.txp = temp_txp & 7;
4020 lmc_timing_params1.s.txp_ext = (temp_txp >> 3) & 1;
David Hendricks2004b932018-03-09 13:58:27 -08004021
4022 lmc_timing_params1.s.twlmrd = divide_roundup(DDR3_tWLMRD*tclk_psecs, 4*tclk_psecs);
4023 lmc_timing_params1.s.twldqsen = divide_roundup(DDR3_tWLDQSEN*tclk_psecs, 4*tclk_psecs);
4024 lmc_timing_params1.s.tfaw = divide_roundup(tfaw, 4*tclk_psecs);
4025 lmc_timing_params1.s.txpdll = divide_roundup(max(10*tclk_psecs, 24000ull), tclk_psecs) - 1;
4026
4027 if ((ddr_type == DDR4_DRAM) && is_3ds_dimm) {
4028 /*
4029 4 Gb: tRFC_DLR = 90 ns
4030 8 Gb: tRFC_DLR = 120 ns
4031 16 Gb: tRFC_DLR = 190 ns FIXME?
4032 */
4033 // RNDUP[tRFC_DLR(ns) / (8 * TCYC(ns))]
4034 if (die_capacity == 0x1000) // 4 Gbit
4035 trfc_dlr = 90;
4036 else if (die_capacity == 0x2000) // 8 Gbit
4037 trfc_dlr = 120;
4038 else if (die_capacity == 0x4000) // 16 Gbit
4039 trfc_dlr = 190;
4040 else
4041 trfc_dlr = 0;
4042
4043 if (trfc_dlr == 0) {
4044 ddr_print("N%d.LMC%d: ERROR: tRFC_DLR: die_capacity %u Mbit is illegal\n",
4045 node, ddr_interface_num, die_capacity);
4046 } else {
4047 lmc_timing_params1.s.trfc_dlr = divide_roundup(trfc_dlr * 1000UL, 8*tclk_psecs);
4048 ddr_print("N%d.LMC%d: TIMING_PARAMS1[trfc_dlr] set to %u\n",
4049 node, ddr_interface_num, lmc_timing_params1.s.trfc_dlr);
4050 }
4051 }
4052
4053 if ((s = lookup_env_parameter_ull("ddr_timing_params1")) != NULL) {
4054 lmc_timing_params1.u = strtoull(s, NULL, 0);
4055 }
David Hendricks7d48ac52018-03-09 14:30:38 -08004056 ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
David Hendricks2004b932018-03-09 13:58:27 -08004057 DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
4058 }
4059
4060 /* LMC(0)_TIMING_PARAMS2 */
4061 if (ddr_type == DDR4_DRAM) {
4062 bdk_lmcx_timing_params1_t lmc_timing_params1;
4063 bdk_lmcx_timing_params2_t lmc_timing_params2;
4064 lmc_timing_params1.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num));
4065 lmc_timing_params2.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS2(ddr_interface_num));
David Hendricks7d48ac52018-03-09 14:30:38 -08004066 ddr_print("TIMING_PARAMS2 : 0x%016llx\n", lmc_timing_params2.u);
David Hendricks2004b932018-03-09 13:58:27 -08004067
4068 //lmc_timing_params2.s.trrd_l = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 1;
David Hendricks7d48ac52018-03-09 14:30:38 -08004069 // NOTE: this is reworked for pass 2.x
4070 int temp_trrd_l = divide_roundup(ddr4_tRRD_Lmin, tclk_psecs) - 2;
David Hendricks2004b932018-03-09 13:58:27 -08004071#if 1
4072 if (temp_trrd_l > 7)
4073 ddr_print("TIMING_PARAMS2[trrd_l]: need extension bit for 0x%x\n", temp_trrd_l);
4074#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08004075 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (temp_trrd_l > 7)) {
4076 temp_trrd_l = 7; // max it out
4077 }
4078 lmc_timing_params2.s.trrd_l = temp_trrd_l & 7;
4079 lmc_timing_params2.s.trrd_l_ext = (temp_trrd_l >> 3) & 1;
David Hendricks2004b932018-03-09 13:58:27 -08004080
4081 lmc_timing_params2.s.twtr_l = divide_nint(max(4*tclk_psecs, 7500ull), tclk_psecs) - 1; // correct for 1600-2400
4082 lmc_timing_params2.s.t_rw_op_max = 7;
4083 lmc_timing_params2.s.trtp = divide_roundup(max(4*tclk_psecs, 7500ull), tclk_psecs) - 1;
4084
David Hendricks7d48ac52018-03-09 14:30:38 -08004085 ddr_print("TIMING_PARAMS2 : 0x%016llx\n", lmc_timing_params2.u);
David Hendricks2004b932018-03-09 13:58:27 -08004086 DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS2(ddr_interface_num), lmc_timing_params2.u);
4087
4088 /* Workaround Errata 25823 - LMC: Possible DDR4 tWTR_L not met
4089 for Write-to-Read operations to the same Bank Group */
4090 if (lmc_timing_params1.s.twtr < (lmc_timing_params2.s.twtr_l - 4)) {
4091 lmc_timing_params1.s.twtr = lmc_timing_params2.s.twtr_l - 4;
David Hendricks7d48ac52018-03-09 14:30:38 -08004092 ddr_print("ERRATA 25823: NEW: TWTR: %d, TWTR_L: %d\n", lmc_timing_params1.s.twtr, lmc_timing_params2.s.twtr_l);
4093 ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
David Hendricks2004b932018-03-09 13:58:27 -08004094 DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
4095 }
4096 }
4097
4098 /* LMC(0)_MODEREG_PARAMS0 */
4099 {
4100 bdk_lmcx_modereg_params0_t lmc_modereg_params0;
4101 int param;
4102
4103 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
4104
4105 if (ddr_type == DDR4_DRAM) {
David Hendricks7d48ac52018-03-09 14:30:38 -08004106 lmc_modereg_params0.s.cwl = 0; /* 1600 (1250ps) */
4107 if (tclk_psecs < 1250)
4108 lmc_modereg_params0.s.cwl = 1; /* 1866 (1072ps) */
4109 if (tclk_psecs < 1072)
4110 lmc_modereg_params0.s.cwl = 2; /* 2133 (938ps) */
4111 if (tclk_psecs < 938)
4112 lmc_modereg_params0.s.cwl = 3; /* 2400 (833ps) */
4113 if (tclk_psecs < 833)
4114 lmc_modereg_params0.s.cwl = 4; /* 2666 (750ps) */
4115 if (tclk_psecs < 750)
4116 lmc_modereg_params0.s.cwl = 5; /* 3200 (625ps) */
David Hendricks2004b932018-03-09 13:58:27 -08004117 } else {
4118 /*
4119 ** CSR CWL CAS write Latency
4120 ** === === =================================
4121 ** 0 5 ( tCK(avg) >= 2.5 ns)
4122 ** 1 6 (2.5 ns > tCK(avg) >= 1.875 ns)
4123 ** 2 7 (1.875 ns > tCK(avg) >= 1.5 ns)
4124 ** 3 8 (1.5 ns > tCK(avg) >= 1.25 ns)
4125 ** 4 9 (1.25 ns > tCK(avg) >= 1.07 ns)
4126 ** 5 10 (1.07 ns > tCK(avg) >= 0.935 ns)
4127 ** 6 11 (0.935 ns > tCK(avg) >= 0.833 ns)
4128 ** 7 12 (0.833 ns > tCK(avg) >= 0.75 ns)
4129 */
4130
4131 lmc_modereg_params0.s.cwl = 0;
4132 if (tclk_psecs < 2500)
4133 lmc_modereg_params0.s.cwl = 1;
4134 if (tclk_psecs < 1875)
4135 lmc_modereg_params0.s.cwl = 2;
4136 if (tclk_psecs < 1500)
4137 lmc_modereg_params0.s.cwl = 3;
4138 if (tclk_psecs < 1250)
4139 lmc_modereg_params0.s.cwl = 4;
4140 if (tclk_psecs < 1070)
4141 lmc_modereg_params0.s.cwl = 5;
4142 if (tclk_psecs < 935)
4143 lmc_modereg_params0.s.cwl = 6;
4144 if (tclk_psecs < 833)
4145 lmc_modereg_params0.s.cwl = 7;
David Hendricks7d48ac52018-03-09 14:30:38 -08004146 }
David Hendricks2004b932018-03-09 13:58:27 -08004147
4148 if ((s = lookup_env_parameter("ddr_cwl")) != NULL) {
4149 lmc_modereg_params0.s.cwl = strtoul(s, NULL, 0) - 5;
4150 }
4151
4152 if (ddr_type == DDR4_DRAM) {
4153 ddr_print("%-45s : %d, [0x%x]\n", "CAS Write Latency CWL, [CSR]",
4154 lmc_modereg_params0.s.cwl + 9
4155 + ((lmc_modereg_params0.s.cwl>2) ? (lmc_modereg_params0.s.cwl-3) * 2 : 0),
4156 lmc_modereg_params0.s.cwl);
4157 } else {
4158 ddr_print("%-45s : %d, [0x%x]\n", "CAS Write Latency CWL, [CSR]",
4159 lmc_modereg_params0.s.cwl + 5,
4160 lmc_modereg_params0.s.cwl);
4161 }
4162
4163 lmc_modereg_params0.s.mprloc = 0;
4164 lmc_modereg_params0.s.mpr = 0;
4165 lmc_modereg_params0.s.dll = (ddr_type == DDR4_DRAM)?1:0; /* disable(0) for DDR3 and enable(1) for DDR4 */
4166 lmc_modereg_params0.s.al = 0;
4167 lmc_modereg_params0.s.wlev = 0; /* Read Only */
4168 lmc_modereg_params0.s.tdqs = ((ddr_type == DDR4_DRAM) || (dram_width != 8))?0:1; /* disable(0) for DDR4 and x4/x16 DDR3 */
4169 lmc_modereg_params0.s.qoff = 0;
4170 //lmc_modereg_params0.s.bl = 0; /* Don't touch block dirty logic */
4171
4172 if ((s = lookup_env_parameter("ddr_cl")) != NULL) {
4173 CL = strtoul(s, NULL, 0);
4174 ddr_print("CAS Latency : %6d\n", CL);
4175 }
4176
4177 if (ddr_type == DDR4_DRAM) {
David Hendricks7d48ac52018-03-09 14:30:38 -08004178 lmc_modereg_params0.s.cl = 0x0;
4179 if (CL > 9)
4180 lmc_modereg_params0.s.cl = 0x1;
4181 if (CL > 10)
4182 lmc_modereg_params0.s.cl = 0x2;
4183 if (CL > 11)
4184 lmc_modereg_params0.s.cl = 0x3;
4185 if (CL > 12)
4186 lmc_modereg_params0.s.cl = 0x4;
4187 if (CL > 13)
4188 lmc_modereg_params0.s.cl = 0x5;
4189 if (CL > 14)
4190 lmc_modereg_params0.s.cl = 0x6;
4191 if (CL > 15)
4192 lmc_modereg_params0.s.cl = 0x7;
4193 if (CL > 16)
4194 lmc_modereg_params0.s.cl = 0x8;
4195 if (CL > 18)
4196 lmc_modereg_params0.s.cl = 0x9;
4197 if (CL > 20)
4198 lmc_modereg_params0.s.cl = 0xA;
4199 if (CL > 24)
4200 lmc_modereg_params0.s.cl = 0xB;
David Hendricks2004b932018-03-09 13:58:27 -08004201 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08004202 lmc_modereg_params0.s.cl = 0x2;
4203 if (CL > 5)
4204 lmc_modereg_params0.s.cl = 0x4;
4205 if (CL > 6)
4206 lmc_modereg_params0.s.cl = 0x6;
4207 if (CL > 7)
4208 lmc_modereg_params0.s.cl = 0x8;
4209 if (CL > 8)
4210 lmc_modereg_params0.s.cl = 0xA;
4211 if (CL > 9)
4212 lmc_modereg_params0.s.cl = 0xC;
4213 if (CL > 10)
4214 lmc_modereg_params0.s.cl = 0xE;
4215 if (CL > 11)
4216 lmc_modereg_params0.s.cl = 0x1;
4217 if (CL > 12)
4218 lmc_modereg_params0.s.cl = 0x3;
4219 if (CL > 13)
4220 lmc_modereg_params0.s.cl = 0x5;
4221 if (CL > 14)
4222 lmc_modereg_params0.s.cl = 0x7;
4223 if (CL > 15)
4224 lmc_modereg_params0.s.cl = 0x9;
4225 }
David Hendricks2004b932018-03-09 13:58:27 -08004226
4227 lmc_modereg_params0.s.rbt = 0; /* Read Only. */
4228 lmc_modereg_params0.s.tm = 0;
4229 lmc_modereg_params0.s.dllr = 0;
4230
4231 param = divide_roundup(twr, tclk_psecs);
4232
4233 if (ddr_type == DDR4_DRAM) { /* DDR4 */
David Hendricks7d48ac52018-03-09 14:30:38 -08004234 lmc_modereg_params0.s.wrp = 1;
4235 if (param > 12)
4236 lmc_modereg_params0.s.wrp = 2;
4237 if (param > 14)
4238 lmc_modereg_params0.s.wrp = 3;
4239 if (param > 16)
4240 lmc_modereg_params0.s.wrp = 4;
4241 if (param > 18)
4242 lmc_modereg_params0.s.wrp = 5;
4243 if (param > 20)
4244 lmc_modereg_params0.s.wrp = 6;
4245 if (param > 24) /* RESERVED in DDR4 spec */
4246 lmc_modereg_params0.s.wrp = 7;
David Hendricks2004b932018-03-09 13:58:27 -08004247 } else { /* DDR3 */
David Hendricks7d48ac52018-03-09 14:30:38 -08004248 lmc_modereg_params0.s.wrp = 1;
4249 if (param > 5)
4250 lmc_modereg_params0.s.wrp = 2;
4251 if (param > 6)
4252 lmc_modereg_params0.s.wrp = 3;
4253 if (param > 7)
4254 lmc_modereg_params0.s.wrp = 4;
4255 if (param > 8)
4256 lmc_modereg_params0.s.wrp = 5;
4257 if (param > 10)
4258 lmc_modereg_params0.s.wrp = 6;
4259 if (param > 12)
4260 lmc_modereg_params0.s.wrp = 7;
4261 }
David Hendricks2004b932018-03-09 13:58:27 -08004262
4263 lmc_modereg_params0.s.ppd = 0;
4264
4265 if ((s = lookup_env_parameter("ddr_wrp")) != NULL) {
4266 lmc_modereg_params0.s.wrp = strtoul(s, NULL, 0);
4267 }
4268
4269 ddr_print("%-45s : %d, [0x%x]\n", "Write recovery for auto precharge WRP, [CSR]",
4270 param, lmc_modereg_params0.s.wrp);
4271
4272 if ((s = lookup_env_parameter_ull("ddr_modereg_params0")) != NULL) {
4273 lmc_modereg_params0.u = strtoull(s, NULL, 0);
4274 }
David Hendricks7d48ac52018-03-09 14:30:38 -08004275 ddr_print("MODEREG_PARAMS0 : 0x%016llx\n", lmc_modereg_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08004276 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
4277 }
4278
4279 /* LMC(0)_MODEREG_PARAMS1 */
4280 {
4281 bdk_lmcx_modereg_params1_t lmc_modereg_params1;
4282
4283 lmc_modereg_params1.u = odt_config[odt_idx].odt_mask1.u;
4284
4285#ifdef CAVIUM_ONLY
4286 /* Special request: mismatched DIMM support. Slot 0: 2-Rank, Slot 1: 1-Rank */
4287 if (rank_mask == 0x7) { /* 2-Rank, 1-Rank */
4288 lmc_modereg_params1.s.rtt_nom_00 = 0;
4289 lmc_modereg_params1.s.rtt_nom_01 = 3; /* rttnom_40ohm */
4290 lmc_modereg_params1.s.rtt_nom_10 = 3; /* rttnom_40ohm */
4291 lmc_modereg_params1.s.rtt_nom_11 = 0;
4292 dyn_rtt_nom_mask = 0x6;
4293 }
4294#endif /* CAVIUM_ONLY */
4295
4296 if ((s = lookup_env_parameter("ddr_rtt_nom_mask")) != NULL) {
4297 dyn_rtt_nom_mask = strtoul(s, NULL, 0);
4298 }
4299
4300
4301 /* Save the original rtt_nom settings before sweeping through settings. */
4302 default_rtt_nom[0] = lmc_modereg_params1.s.rtt_nom_00;
4303 default_rtt_nom[1] = lmc_modereg_params1.s.rtt_nom_01;
4304 default_rtt_nom[2] = lmc_modereg_params1.s.rtt_nom_10;
4305 default_rtt_nom[3] = lmc_modereg_params1.s.rtt_nom_11;
4306
4307 ddr_rtt_nom_auto = custom_lmc_config->ddr_rtt_nom_auto;
4308
4309 for (i=0; i<4; ++i) {
4310 uint64_t value;
4311 if ((s = lookup_env_parameter("ddr_rtt_nom_%1d%1d", !!(i&2), !!(i&1))) == NULL)
4312 s = lookup_env_parameter("ddr%d_rtt_nom_%1d%1d", ddr_interface_num, !!(i&2), !!(i&1));
4313 if (s != NULL) {
4314 value = strtoul(s, NULL, 0);
4315 lmc_modereg_params1.u &= ~((uint64_t)0x7 << (i*12+9));
4316 lmc_modereg_params1.u |= ( (value & 0x7) << (i*12+9));
4317 default_rtt_nom[i] = value;
4318 ddr_rtt_nom_auto = 0;
4319 }
4320 }
4321
4322 if ((s = lookup_env_parameter("ddr_rtt_nom")) == NULL)
4323 s = lookup_env_parameter("ddr%d_rtt_nom", ddr_interface_num);
4324 if (s != NULL) {
4325 uint64_t value;
4326 value = strtoul(s, NULL, 0);
4327
4328 if (dyn_rtt_nom_mask & 1)
4329 default_rtt_nom[0] = lmc_modereg_params1.s.rtt_nom_00 = value;
4330 if (dyn_rtt_nom_mask & 2)
4331 default_rtt_nom[1] = lmc_modereg_params1.s.rtt_nom_01 = value;
4332 if (dyn_rtt_nom_mask & 4)
4333 default_rtt_nom[2] = lmc_modereg_params1.s.rtt_nom_10 = value;
4334 if (dyn_rtt_nom_mask & 8)
4335 default_rtt_nom[3] = lmc_modereg_params1.s.rtt_nom_11 = value;
4336
4337 ddr_rtt_nom_auto = 0;
4338 }
4339
4340 if ((s = lookup_env_parameter("ddr_rtt_wr")) != NULL) {
4341 uint64_t value = strtoul(s, NULL, 0);
4342 for (i=0; i<4; ++i) {
4343 INSRT_WR(&lmc_modereg_params1.u, i, value);
4344 }
4345 }
4346
4347 for (i = 0; i < 4; ++i) {
4348 uint64_t value;
4349 if ((s = lookup_env_parameter("ddr_rtt_wr_%1d%1d", !!(i&2), !!(i&1))) == NULL)
4350 s = lookup_env_parameter("ddr%d_rtt_wr_%1d%1d", ddr_interface_num, !!(i&2), !!(i&1));
4351 if (s != NULL) {
4352 value = strtoul(s, NULL, 0);
4353 INSRT_WR(&lmc_modereg_params1.u, i, value);
4354 }
4355 }
4356
4357 // Make sure pass 1 has valid RTT_WR settings, because
4358 // configuration files may be set-up for pass 2, and
4359 // pass 1 supports no RTT_WR extension bits
4360 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) {
4361 for (i = 0; i < 4; ++i) {
4362 if (EXTR_WR(lmc_modereg_params1.u, i) > 3) { // if 80 or undefined
4363 INSRT_WR(&lmc_modereg_params1.u, i, 1); // FIXME? always insert 120
4364 ddr_print("RTT_WR_%d%d set to 120 for CN88XX pass 1\n", !!(i&2), i&1);
4365 }
4366 }
4367 }
4368 if ((s = lookup_env_parameter("ddr_dic")) != NULL) {
4369 uint64_t value = strtoul(s, NULL, 0);
4370 for (i=0; i<4; ++i) {
4371 lmc_modereg_params1.u &= ~((uint64_t)0x3 << (i*12+7));
4372 lmc_modereg_params1.u |= ( (value & 0x3) << (i*12+7));
4373 }
4374 }
4375
4376 for (i=0; i<4; ++i) {
4377 uint64_t value;
4378 if ((s = lookup_env_parameter("ddr_dic_%1d%1d", !!(i&2), !!(i&1))) != NULL) {
4379 value = strtoul(s, NULL, 0);
4380 lmc_modereg_params1.u &= ~((uint64_t)0x3 << (i*12+7));
4381 lmc_modereg_params1.u |= ( (value & 0x3) << (i*12+7));
4382 }
4383 }
4384
4385 if ((s = lookup_env_parameter_ull("ddr_modereg_params1")) != NULL) {
4386 lmc_modereg_params1.u = strtoull(s, NULL, 0);
4387 }
4388
4389 ddr_print("RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
4390 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
4391 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
4392 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
4393 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00],
4394 lmc_modereg_params1.s.rtt_nom_11,
4395 lmc_modereg_params1.s.rtt_nom_10,
4396 lmc_modereg_params1.s.rtt_nom_01,
4397 lmc_modereg_params1.s.rtt_nom_00);
4398
4399 ddr_print("RTT_WR %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
4400 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 3)],
4401 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 2)],
4402 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 1)],
4403 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 0)],
4404 EXTR_WR(lmc_modereg_params1.u, 3),
4405 EXTR_WR(lmc_modereg_params1.u, 2),
4406 EXTR_WR(lmc_modereg_params1.u, 1),
4407 EXTR_WR(lmc_modereg_params1.u, 0));
4408
4409 ddr_print("DIC %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
4410 imp_values->dic_ohms[lmc_modereg_params1.s.dic_11],
4411 imp_values->dic_ohms[lmc_modereg_params1.s.dic_10],
4412 imp_values->dic_ohms[lmc_modereg_params1.s.dic_01],
4413 imp_values->dic_ohms[lmc_modereg_params1.s.dic_00],
4414 lmc_modereg_params1.s.dic_11,
4415 lmc_modereg_params1.s.dic_10,
4416 lmc_modereg_params1.s.dic_01,
4417 lmc_modereg_params1.s.dic_00);
4418
David Hendricks7d48ac52018-03-09 14:30:38 -08004419 ddr_print("MODEREG_PARAMS1 : 0x%016llx\n", lmc_modereg_params1.u);
David Hendricks2004b932018-03-09 13:58:27 -08004420 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
4421
4422 } /* LMC(0)_MODEREG_PARAMS1 */
4423
4424 /* LMC(0)_MODEREG_PARAMS2 */
4425 if (ddr_type == DDR4_DRAM) {
David Hendricks7d48ac52018-03-09 14:30:38 -08004426 bdk_lmcx_modereg_params2_t lmc_modereg_params2;
4427 lmc_modereg_params2.u = odt_config[odt_idx].odt_mask2.u;
David Hendricks2004b932018-03-09 13:58:27 -08004428
David Hendricks7d48ac52018-03-09 14:30:38 -08004429 for (i=0; i<4; ++i) {
4430 uint64_t value;
4431 if ((s = lookup_env_parameter("ddr_rtt_park_%1d%1d", !!(i&2), !!(i&1))) != NULL) {
4432 value = strtoul(s, NULL, 0);
4433 lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
4434 lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
4435 }
4436 }
David Hendricks2004b932018-03-09 13:58:27 -08004437
David Hendricks7d48ac52018-03-09 14:30:38 -08004438 if ((s = lookup_env_parameter("ddr_rtt_park")) != NULL) {
4439 uint64_t value = strtoul(s, NULL, 0);
4440 for (i=0; i<4; ++i) {
4441 lmc_modereg_params2.u &= ~((uint64_t)0x7 << (i*10+0));
4442 lmc_modereg_params2.u |= ( (value & 0x7) << (i*10+0));
4443 }
4444 }
David Hendricks2004b932018-03-09 13:58:27 -08004445
David Hendricks7d48ac52018-03-09 14:30:38 -08004446 if ((s = lookup_env_parameter_ull("ddr_modereg_params2")) != NULL) {
4447 lmc_modereg_params2.u = strtoull(s, NULL, 0);
4448 }
David Hendricks2004b932018-03-09 13:58:27 -08004449
David Hendricks7d48ac52018-03-09 14:30:38 -08004450 ddr_print("RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
4451 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
4452 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
4453 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
4454 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
4455 lmc_modereg_params2.s.rtt_park_11,
4456 lmc_modereg_params2.s.rtt_park_10,
4457 lmc_modereg_params2.s.rtt_park_01,
4458 lmc_modereg_params2.s.rtt_park_00);
David Hendricks2004b932018-03-09 13:58:27 -08004459
David Hendricks7d48ac52018-03-09 14:30:38 -08004460 ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
4461 lmc_modereg_params2.s.vref_range_11,
4462 lmc_modereg_params2.s.vref_range_10,
4463 lmc_modereg_params2.s.vref_range_01,
4464 lmc_modereg_params2.s.vref_range_00);
David Hendricks2004b932018-03-09 13:58:27 -08004465
David Hendricks7d48ac52018-03-09 14:30:38 -08004466 ddr_print("%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
4467 lmc_modereg_params2.s.vref_value_11,
4468 lmc_modereg_params2.s.vref_value_10,
4469 lmc_modereg_params2.s.vref_value_01,
4470 lmc_modereg_params2.s.vref_value_00);
David Hendricks2004b932018-03-09 13:58:27 -08004471
David Hendricks7d48ac52018-03-09 14:30:38 -08004472 ddr_print("MODEREG_PARAMS2 : 0x%016llx\n", lmc_modereg_params2.u);
4473 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num), lmc_modereg_params2.u);
David Hendricks2004b932018-03-09 13:58:27 -08004474
4475 } /* LMC(0)_MODEREG_PARAMS2 */
4476
4477 /* LMC(0)_MODEREG_PARAMS3 */
4478 if (ddr_type == DDR4_DRAM) {
4479 bdk_lmcx_modereg_params3_t lmc_modereg_params3;
4480
4481 lmc_modereg_params3.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS3(ddr_interface_num));
4482
4483 //lmc_modereg_params3.s.max_pd =
4484 //lmc_modereg_params3.s.tc_ref =
4485 //lmc_modereg_params3.s.vref_mon =
4486 //lmc_modereg_params3.s.cal =
4487 //lmc_modereg_params3.s.sre_abort =
4488 //lmc_modereg_params3.s.rd_preamble =
4489 //lmc_modereg_params3.s.wr_preamble =
4490 //lmc_modereg_params3.s.par_lat_mode =
4491 //lmc_modereg_params3.s.odt_pd =
4492 //lmc_modereg_params3.s.ca_par_pers =
4493 //lmc_modereg_params3.s.dm =
4494 //lmc_modereg_params3.s.wr_dbi =
4495 //lmc_modereg_params3.s.rd_dbi =
4496 lmc_modereg_params3.s.tccd_l = max(divide_roundup(ddr4_tCCD_Lmin, tclk_psecs), 5ull) - 4;
4497 //lmc_modereg_params3.s.lpasr =
4498 //lmc_modereg_params3.s.crc =
4499 //lmc_modereg_params3.s.gd =
4500 //lmc_modereg_params3.s.pda =
4501 //lmc_modereg_params3.s.temp_sense =
4502 //lmc_modereg_params3.s.fgrm =
4503 //lmc_modereg_params3.s.wr_cmd_lat =
4504 //lmc_modereg_params3.s.mpr_fmt =
4505
4506 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) {
4507 int delay = 0;
4508 if ((lranks_per_prank == 4) && (ddr_hertz >= 1000000000))
4509 delay = 1;
4510 lmc_modereg_params3.s.xrank_add_tccd_l = delay;
4511 lmc_modereg_params3.s.xrank_add_tccd_s = delay;
4512 }
4513
David Hendricks7d48ac52018-03-09 14:30:38 -08004514 ddr_print("MODEREG_PARAMS3 : 0x%016llx\n", lmc_modereg_params3.u);
David Hendricks2004b932018-03-09 13:58:27 -08004515 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS3(ddr_interface_num), lmc_modereg_params3.u);
4516 } /* LMC(0)_MODEREG_PARAMS3 */
4517
4518 /* LMC(0)_NXM */
4519 {
4520 bdk_lmcx_nxm_t lmc_nxm;
4521 int num_bits = row_lsb + row_bits + lranks_bits - 26;
4522 lmc_nxm.u = BDK_CSR_READ(node, BDK_LMCX_NXM(ddr_interface_num));
4523
4524 if (rank_mask & 0x1)
4525 lmc_nxm.s.mem_msb_d0_r0 = num_bits;
4526 if (rank_mask & 0x2)
4527 lmc_nxm.s.mem_msb_d0_r1 = num_bits;
4528 if (rank_mask & 0x4)
4529 lmc_nxm.s.mem_msb_d1_r0 = num_bits;
4530 if (rank_mask & 0x8)
4531 lmc_nxm.s.mem_msb_d1_r1 = num_bits;
4532
4533 lmc_nxm.s.cs_mask = ~rank_mask & 0xff; /* Set the mask for non-existant ranks. */
4534
4535 if ((s = lookup_env_parameter_ull("ddr_nxm")) != NULL) {
4536 lmc_nxm.u = strtoull(s, NULL, 0);
4537 }
David Hendricks7d48ac52018-03-09 14:30:38 -08004538 ddr_print("LMC_NXM : 0x%016llx\n", lmc_nxm.u);
David Hendricks2004b932018-03-09 13:58:27 -08004539 DRAM_CSR_WRITE(node, BDK_LMCX_NXM(ddr_interface_num), lmc_nxm.u);
4540 }
4541
4542 /* LMC(0)_WODT_MASK */
4543 {
4544 bdk_lmcx_wodt_mask_t lmc_wodt_mask;
4545 lmc_wodt_mask.u = odt_config[odt_idx].odt_mask;
4546
4547 if ((s = lookup_env_parameter_ull("ddr_wodt_mask")) != NULL) {
4548 lmc_wodt_mask.u = strtoull(s, NULL, 0);
4549 }
4550
David Hendricks7d48ac52018-03-09 14:30:38 -08004551 ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
David Hendricks2004b932018-03-09 13:58:27 -08004552 DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
4553 }
4554
4555 /* LMC(0)_RODT_MASK */
4556 {
4557 int rankx;
4558 bdk_lmcx_rodt_mask_t lmc_rodt_mask;
4559 lmc_rodt_mask.u = odt_config[odt_idx].rodt_ctl;
4560
4561 if ((s = lookup_env_parameter_ull("ddr_rodt_mask")) != NULL) {
4562 lmc_rodt_mask.u = strtoull(s, NULL, 0);
4563 }
4564
David Hendricks7d48ac52018-03-09 14:30:38 -08004565 ddr_print("%-45s : 0x%016llx\n", "RODT_MASK", lmc_rodt_mask.u);
4566 DRAM_CSR_WRITE(node, BDK_LMCX_RODT_MASK(ddr_interface_num), lmc_rodt_mask.u);
David Hendricks2004b932018-03-09 13:58:27 -08004567
4568 dyn_rtt_nom_mask = 0;
4569 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
4570 if (!(rank_mask & (1 << rankx)))
4571 continue;
4572 dyn_rtt_nom_mask |= ((lmc_rodt_mask.u >> (8*rankx)) & 0xff);
4573 }
4574 if (num_ranks == 4) {
4575 /* Normally ODT1 is wired to rank 1. For quad-ranked DIMMs
4576 ODT1 is wired to the third rank (rank 2). The mask,
4577 dyn_rtt_nom_mask, is used to indicate for which ranks
4578 to sweep RTT_NOM during read-leveling. Shift the bit
4579 from the ODT1 position over to the "ODT2" position so
4580 that the read-leveling analysis comes out right. */
4581 int odt1_bit = dyn_rtt_nom_mask & 2;
4582 dyn_rtt_nom_mask &= ~2;
4583 dyn_rtt_nom_mask |= odt1_bit<<1;
4584 }
4585 ddr_print("%-45s : 0x%02x\n", "DYN_RTT_NOM_MASK", dyn_rtt_nom_mask);
4586 }
4587
4588 /* LMC(0)_COMP_CTL2 */
4589 {
4590 bdk_lmcx_comp_ctl2_t comp_ctl2;
4591
4592 comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
4593
David Hendricks7d48ac52018-03-09 14:30:38 -08004594 comp_ctl2.s.dqx_ctl = odt_config[odt_idx].odt_ena;
4595 comp_ctl2.s.ck_ctl = (custom_lmc_config->ck_ctl == 0) ? 4 : custom_lmc_config->ck_ctl; /* Default 4=34.3 ohm */
4596 comp_ctl2.s.cmd_ctl = (custom_lmc_config->cmd_ctl == 0) ? 4 : custom_lmc_config->cmd_ctl; /* Default 4=34.3 ohm */
4597 comp_ctl2.s.control_ctl = (custom_lmc_config->ctl_ctl == 0) ? 4 : custom_lmc_config->ctl_ctl; /* Default 4=34.3 ohm */
David Hendricks2004b932018-03-09 13:58:27 -08004598
David Hendricks7d48ac52018-03-09 14:30:38 -08004599 // NOTE: these are now done earlier, in Step 6.9.3
David Hendricks2004b932018-03-09 13:58:27 -08004600 // comp_ctl2.s.ntune_offset = 0;
4601 // comp_ctl2.s.ptune_offset = 0;
4602
4603 ddr_rodt_ctl_auto = custom_lmc_config->ddr_rodt_ctl_auto;
4604 if ((s = lookup_env_parameter("ddr_rodt_ctl_auto")) != NULL) {
4605 ddr_rodt_ctl_auto = !!strtoul(s, NULL, 0);
4606 }
4607
4608 default_rodt_ctl = odt_config[odt_idx].qs_dic;
4609 if ((s = lookup_env_parameter("ddr_rodt_ctl")) == NULL)
4610 s = lookup_env_parameter("ddr%d_rodt_ctl", ddr_interface_num);
4611 if (s != NULL) {
4612 default_rodt_ctl = strtoul(s, NULL, 0);
4613 ddr_rodt_ctl_auto = 0;
4614 }
4615
4616 comp_ctl2.s.rodt_ctl = default_rodt_ctl;
4617
David Hendricks7d48ac52018-03-09 14:30:38 -08004618 // if DDR4, force CK_CTL to 26 ohms if it is currently 34 ohms, and DCLK speed is 1 GHz or more...
4619 if ((ddr_type == DDR4_DRAM) && (comp_ctl2.s.ck_ctl == ddr4_driver_34_ohm) && (ddr_hertz >= 1000000000)) {
4620 comp_ctl2.s.ck_ctl = ddr4_driver_26_ohm; // lowest for DDR4 is 26 ohms
4621 ddr_print("Forcing DDR4 COMP_CTL2[CK_CTL] to %d, %d ohms\n", comp_ctl2.s.ck_ctl,
4622 imp_values->drive_strength[comp_ctl2.s.ck_ctl]);
4623 }
David Hendricks2004b932018-03-09 13:58:27 -08004624
4625 if ((s = lookup_env_parameter("ddr_ck_ctl")) != NULL) {
4626 comp_ctl2.s.ck_ctl = strtoul(s, NULL, 0);
4627 }
4628
4629 if ((s = lookup_env_parameter("ddr_cmd_ctl")) != NULL) {
4630 comp_ctl2.s.cmd_ctl = strtoul(s, NULL, 0);
4631 }
4632
4633 if ((s = lookup_env_parameter("ddr_control_ctl")) != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08004634 comp_ctl2.s.control_ctl = strtoul(s, NULL, 0);
David Hendricks2004b932018-03-09 13:58:27 -08004635 }
4636
4637 if ((s = lookup_env_parameter("ddr_dqx_ctl")) != NULL) {
4638 comp_ctl2.s.dqx_ctl = strtoul(s, NULL, 0);
4639 }
4640
4641 ddr_print("%-45s : %d, %d ohms\n", "DQX_CTL ", comp_ctl2.s.dqx_ctl,
David Hendricks7d48ac52018-03-09 14:30:38 -08004642 imp_values->dqx_strength [comp_ctl2.s.dqx_ctl ]);
David Hendricks2004b932018-03-09 13:58:27 -08004643 ddr_print("%-45s : %d, %d ohms\n", "CK_CTL ", comp_ctl2.s.ck_ctl,
David Hendricks7d48ac52018-03-09 14:30:38 -08004644 imp_values->drive_strength[comp_ctl2.s.ck_ctl ]);
David Hendricks2004b932018-03-09 13:58:27 -08004645 ddr_print("%-45s : %d, %d ohms\n", "CMD_CTL ", comp_ctl2.s.cmd_ctl,
David Hendricks7d48ac52018-03-09 14:30:38 -08004646 imp_values->drive_strength[comp_ctl2.s.cmd_ctl ]);
David Hendricks2004b932018-03-09 13:58:27 -08004647 ddr_print("%-45s : %d, %d ohms\n", "CONTROL_CTL ", comp_ctl2.s.control_ctl,
David Hendricks7d48ac52018-03-09 14:30:38 -08004648 imp_values->drive_strength[comp_ctl2.s.control_ctl]);
David Hendricks2004b932018-03-09 13:58:27 -08004649 ddr_print("Read ODT_CTL : 0x%x (%d ohms)\n",
4650 comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[comp_ctl2.s.rodt_ctl]);
4651
4652 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), comp_ctl2.u);
4653 }
4654
4655 /* LMC(0)_PHY_CTL */
4656 {
4657 bdk_lmcx_phy_ctl_t lmc_phy_ctl;
4658 lmc_phy_ctl.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL(ddr_interface_num));
4659 lmc_phy_ctl.s.ts_stagger = 0;
4660
4661 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (lranks_per_prank > 1)) {
4662 lmc_phy_ctl.cn81xx.c0_sel = lmc_phy_ctl.cn81xx.c1_sel = 2; // C0 is TEN, C1 is A17
4663 ddr_print("N%d.LMC%d: 3DS: setting PHY_CTL[cx_csel] = %d\n",
4664 node, ddr_interface_num, lmc_phy_ctl.cn81xx.c1_sel);
4665 }
4666
David Hendricks7d48ac52018-03-09 14:30:38 -08004667 ddr_print("PHY_CTL : 0x%016llx\n", lmc_phy_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08004668 DRAM_CSR_WRITE(node, BDK_LMCX_PHY_CTL(ddr_interface_num), lmc_phy_ctl.u);
4669 }
4670
4671 /* LMC(0)_DIMM0/1_PARAMS */
4672 if (spd_rdimm) {
4673 bdk_lmcx_dimm_ctl_t lmc_dimm_ctl;
4674
4675 for (didx = 0; didx < (unsigned)dimm_count; ++didx) {
David Hendricks7d48ac52018-03-09 14:30:38 -08004676 bdk_lmcx_dimmx_params_t lmc_dimmx_params;
4677 int dimm = didx;
4678 int rc;
David Hendricks2004b932018-03-09 13:58:27 -08004679
David Hendricks7d48ac52018-03-09 14:30:38 -08004680 lmc_dimmx_params.u = BDK_CSR_READ(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm));
David Hendricks2004b932018-03-09 13:58:27 -08004681
4682
4683 if (ddr_type == DDR4_DRAM) {
4684
4685 bdk_lmcx_dimmx_ddr4_params0_t lmc_dimmx_ddr4_params0;
4686 bdk_lmcx_dimmx_ddr4_params1_t lmc_dimmx_ddr4_params1;
4687 bdk_lmcx_ddr4_dimm_ctl_t lmc_ddr4_dimm_ctl;
4688
4689 lmc_dimmx_params.s.rc0 = 0;
4690 lmc_dimmx_params.s.rc1 = 0;
4691 lmc_dimmx_params.s.rc2 = 0;
4692
4693 rc = read_spd(node, &dimm_config_table[didx], DDR4_SPD_RDIMM_REGISTER_DRIVE_STRENGTH_CTL);
4694 lmc_dimmx_params.s.rc3 = (rc >> 4) & 0xf;
4695 lmc_dimmx_params.s.rc4 = ((rc >> 0) & 0x3) << 2;
4696 lmc_dimmx_params.s.rc4 |= ((rc >> 2) & 0x3) << 0;
4697
4698 rc = read_spd(node, &dimm_config_table[didx], DDR4_SPD_RDIMM_REGISTER_DRIVE_STRENGTH_CK);
4699 lmc_dimmx_params.s.rc5 = ((rc >> 0) & 0x3) << 2;
4700 lmc_dimmx_params.s.rc5 |= ((rc >> 2) & 0x3) << 0;
4701
4702 lmc_dimmx_params.s.rc6 = 0;
4703 lmc_dimmx_params.s.rc7 = 0;
4704 lmc_dimmx_params.s.rc8 = 0;
4705 lmc_dimmx_params.s.rc9 = 0;
4706
4707 /*
4708 ** rc10 DDR4 RDIMM Operating Speed
4709 ** ==== =========================================================
4710 ** 0 tclk_psecs >= 1250 psec DDR4-1600 (1250 ps)
4711 ** 1 1250 psec > tclk_psecs >= 1071 psec DDR4-1866 (1071 ps)
4712 ** 2 1071 psec > tclk_psecs >= 938 psec DDR4-2133 ( 938 ps)
4713 ** 3 938 psec > tclk_psecs >= 833 psec DDR4-2400 ( 833 ps)
4714 ** 4 833 psec > tclk_psecs >= 750 psec DDR4-2666 ( 750 ps)
4715 ** 5 750 psec > tclk_psecs >= 625 psec DDR4-3200 ( 625 ps)
4716 */
4717 lmc_dimmx_params.s.rc10 = 0;
4718 if (1250 > tclk_psecs)
4719 lmc_dimmx_params.s.rc10 = 1;
4720 if (1071 > tclk_psecs)
4721 lmc_dimmx_params.s.rc10 = 2;
4722 if (938 > tclk_psecs)
4723 lmc_dimmx_params.s.rc10 = 3;
4724 if (833 > tclk_psecs)
4725 lmc_dimmx_params.s.rc10 = 4;
4726 if (750 > tclk_psecs)
4727 lmc_dimmx_params.s.rc10 = 5;
4728
4729 lmc_dimmx_params.s.rc11 = 0;
4730 lmc_dimmx_params.s.rc12 = 0;
David Hendricks7d48ac52018-03-09 14:30:38 -08004731 lmc_dimmx_params.s.rc13 = (spd_dimm_type == 4) ? 0 : 4; /* 0=LRDIMM, 1=RDIMM */
4732 lmc_dimmx_params.s.rc13 |= (ddr_type == DDR4_DRAM) ? (spd_addr_mirror << 3) : 0;
David Hendricks2004b932018-03-09 13:58:27 -08004733 lmc_dimmx_params.s.rc14 = 0;
4734 //lmc_dimmx_params.s.rc15 = 4; /* 0 nCK latency adder */
4735 lmc_dimmx_params.s.rc15 = 0; /* 1 nCK latency adder */
4736
4737 lmc_dimmx_ddr4_params0.u = 0;
4738
4739 lmc_dimmx_ddr4_params0.s.rc8x = 0;
4740 lmc_dimmx_ddr4_params0.s.rc7x = 0;
4741 lmc_dimmx_ddr4_params0.s.rc6x = 0;
4742 lmc_dimmx_ddr4_params0.s.rc5x = 0;
4743 lmc_dimmx_ddr4_params0.s.rc4x = 0;
4744
4745 lmc_dimmx_ddr4_params0.s.rc3x = compute_rc3x(tclk_psecs);
4746
4747 lmc_dimmx_ddr4_params0.s.rc2x = 0;
4748 lmc_dimmx_ddr4_params0.s.rc1x = 0;
4749
4750 lmc_dimmx_ddr4_params1.u = 0;
4751
4752 lmc_dimmx_ddr4_params1.s.rcbx = 0;
4753 lmc_dimmx_ddr4_params1.s.rcax = 0;
4754 lmc_dimmx_ddr4_params1.s.rc9x = 0;
4755
4756 lmc_ddr4_dimm_ctl.u = 0;
4757 lmc_ddr4_dimm_ctl.s.ddr4_dimm0_wmask = 0x004;
4758 lmc_ddr4_dimm_ctl.s.ddr4_dimm1_wmask = (dimm_count > 1) ? 0x004 : 0x0000;
4759
David Hendricks7d48ac52018-03-09 14:30:38 -08004760 /*
4761 * Handle any overrides from envvars here...
4762 */
4763 if ((s = lookup_env_parameter("ddr_ddr4_params0")) != NULL) {
4764 lmc_dimmx_ddr4_params0.u = strtoul(s, NULL, 0);
4765 }
David Hendricks2004b932018-03-09 13:58:27 -08004766
David Hendricks7d48ac52018-03-09 14:30:38 -08004767 if ((s = lookup_env_parameter("ddr_ddr4_params1")) != NULL) {
4768 lmc_dimmx_ddr4_params1.u = strtoul(s, NULL, 0);
4769 }
David Hendricks2004b932018-03-09 13:58:27 -08004770
David Hendricks7d48ac52018-03-09 14:30:38 -08004771 if ((s = lookup_env_parameter("ddr_ddr4_dimm_ctl")) != NULL) {
4772 lmc_ddr4_dimm_ctl.u = strtoul(s, NULL, 0);
4773 }
David Hendricks2004b932018-03-09 13:58:27 -08004774
David Hendricks7d48ac52018-03-09 14:30:38 -08004775 for (i=0; i<11; ++i) {
4776 uint64_t value;
4777 if ((s = lookup_env_parameter("ddr_ddr4_rc%1xx", i+1)) != NULL) {
4778 value = strtoul(s, NULL, 0);
4779 if (i < 8) {
4780 lmc_dimmx_ddr4_params0.u &= ~((uint64_t)0xff << (i*8));
4781 lmc_dimmx_ddr4_params0.u |= (value << (i*8));
4782 } else {
4783 lmc_dimmx_ddr4_params1.u &= ~((uint64_t)0xff << ((i-8)*8));
4784 lmc_dimmx_ddr4_params1.u |= (value << ((i-8)*8));
4785 }
4786 }
4787 }
David Hendricks2004b932018-03-09 13:58:27 -08004788
David Hendricks7d48ac52018-03-09 14:30:38 -08004789 /*
4790 * write the final CSR values
4791 */
David Hendricks2004b932018-03-09 13:58:27 -08004792 DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_DDR4_PARAMS0(ddr_interface_num, dimm), lmc_dimmx_ddr4_params0.u);
4793
4794 DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), lmc_ddr4_dimm_ctl.u);
4795
4796 DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_DDR4_PARAMS1(ddr_interface_num, dimm), lmc_dimmx_ddr4_params1.u);
4797
4798 ddr_print("DIMM%d Register Control Words RCBx:RC1x : %x %x %x %x %x %x %x %x %x %x %x\n",
4799 dimm,
4800 lmc_dimmx_ddr4_params1.s.rcbx,
4801 lmc_dimmx_ddr4_params1.s.rcax,
4802 lmc_dimmx_ddr4_params1.s.rc9x,
4803 lmc_dimmx_ddr4_params0.s.rc8x,
4804 lmc_dimmx_ddr4_params0.s.rc7x,
4805 lmc_dimmx_ddr4_params0.s.rc6x,
4806 lmc_dimmx_ddr4_params0.s.rc5x,
4807 lmc_dimmx_ddr4_params0.s.rc4x,
4808 lmc_dimmx_ddr4_params0.s.rc3x,
4809 lmc_dimmx_ddr4_params0.s.rc2x,
4810 lmc_dimmx_ddr4_params0.s.rc1x );
4811
4812 } else { /* if (ddr_type == DDR4_DRAM) */
David Hendricks7d48ac52018-03-09 14:30:38 -08004813 rc = read_spd(node, &dimm_config_table[didx], 69);
4814 lmc_dimmx_params.s.rc0 = (rc >> 0) & 0xf;
4815 lmc_dimmx_params.s.rc1 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004816
David Hendricks7d48ac52018-03-09 14:30:38 -08004817 rc = read_spd(node, &dimm_config_table[didx], 70);
4818 lmc_dimmx_params.s.rc2 = (rc >> 0) & 0xf;
4819 lmc_dimmx_params.s.rc3 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004820
David Hendricks7d48ac52018-03-09 14:30:38 -08004821 rc = read_spd(node, &dimm_config_table[didx], 71);
4822 lmc_dimmx_params.s.rc4 = (rc >> 0) & 0xf;
4823 lmc_dimmx_params.s.rc5 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004824
David Hendricks7d48ac52018-03-09 14:30:38 -08004825 rc = read_spd(node, &dimm_config_table[didx], 72);
4826 lmc_dimmx_params.s.rc6 = (rc >> 0) & 0xf;
4827 lmc_dimmx_params.s.rc7 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004828
David Hendricks7d48ac52018-03-09 14:30:38 -08004829 rc = read_spd(node, &dimm_config_table[didx], 73);
4830 lmc_dimmx_params.s.rc8 = (rc >> 0) & 0xf;
4831 lmc_dimmx_params.s.rc9 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004832
David Hendricks7d48ac52018-03-09 14:30:38 -08004833 rc = read_spd(node, &dimm_config_table[didx], 74);
4834 lmc_dimmx_params.s.rc10 = (rc >> 0) & 0xf;
4835 lmc_dimmx_params.s.rc11 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004836
David Hendricks7d48ac52018-03-09 14:30:38 -08004837 rc = read_spd(node, &dimm_config_table[didx], 75);
4838 lmc_dimmx_params.s.rc12 = (rc >> 0) & 0xf;
4839 lmc_dimmx_params.s.rc13 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004840
David Hendricks7d48ac52018-03-09 14:30:38 -08004841 rc = read_spd(node, &dimm_config_table[didx], 76);
4842 lmc_dimmx_params.s.rc14 = (rc >> 0) & 0xf;
4843 lmc_dimmx_params.s.rc15 = (rc >> 4) & 0xf;
David Hendricks2004b932018-03-09 13:58:27 -08004844
4845
David Hendricks7d48ac52018-03-09 14:30:38 -08004846 if ((s = lookup_env_parameter("ddr_clk_drive")) != NULL) {
4847 if (strcmp(s,"light") == 0) {
4848 lmc_dimmx_params.s.rc5 = 0x0; /* Light Drive */
4849 }
4850 if (strcmp(s,"moderate") == 0) {
4851 lmc_dimmx_params.s.rc5 = 0x5; /* Moderate Drive */
4852 }
4853 if (strcmp(s,"strong") == 0) {
4854 lmc_dimmx_params.s.rc5 = 0xA; /* Strong Drive */
4855 }
4856 }
David Hendricks2004b932018-03-09 13:58:27 -08004857
David Hendricks7d48ac52018-03-09 14:30:38 -08004858 if ((s = lookup_env_parameter("ddr_cmd_drive")) != NULL) {
4859 if (strcmp(s,"light") == 0) {
4860 lmc_dimmx_params.s.rc3 = 0x0; /* Light Drive */
4861 }
4862 if (strcmp(s,"moderate") == 0) {
4863 lmc_dimmx_params.s.rc3 = 0x5; /* Moderate Drive */
4864 }
4865 if (strcmp(s,"strong") == 0) {
4866 lmc_dimmx_params.s.rc3 = 0xA; /* Strong Drive */
4867 }
4868 }
David Hendricks2004b932018-03-09 13:58:27 -08004869
David Hendricks7d48ac52018-03-09 14:30:38 -08004870 if ((s = lookup_env_parameter("ddr_ctl_drive")) != NULL) {
4871 if (strcmp(s,"light") == 0) {
4872 lmc_dimmx_params.s.rc4 = 0x0; /* Light Drive */
4873 }
4874 if (strcmp(s,"moderate") == 0) {
4875 lmc_dimmx_params.s.rc4 = 0x5; /* Moderate Drive */
4876 }
4877 }
David Hendricks2004b932018-03-09 13:58:27 -08004878
4879
4880 /*
4881 ** rc10 DDR3 RDIMM Operating Speed
4882 ** ==== =========================================================
4883 ** 0 tclk_psecs >= 2500 psec DDR3/DDR3L-800 (default)
4884 ** 1 2500 psec > tclk_psecs >= 1875 psec DDR3/DDR3L-1066
4885 ** 2 1875 psec > tclk_psecs >= 1500 psec DDR3/DDR3L-1333
4886 ** 3 1500 psec > tclk_psecs >= 1250 psec DDR3/DDR3L-1600
4887 ** 4 1250 psec > tclk_psecs >= 1071 psec DDR3-1866
4888 */
4889 lmc_dimmx_params.s.rc10 = 0;
4890 if (2500 > tclk_psecs)
4891 lmc_dimmx_params.s.rc10 = 1;
4892 if (1875 > tclk_psecs)
4893 lmc_dimmx_params.s.rc10 = 2;
4894 if (1500 > tclk_psecs)
4895 lmc_dimmx_params.s.rc10 = 3;
4896 if (1250 > tclk_psecs)
4897 lmc_dimmx_params.s.rc10 = 4;
4898
David Hendricks7d48ac52018-03-09 14:30:38 -08004899 } /* if (ddr_type == DDR4_DRAM) */
David Hendricks2004b932018-03-09 13:58:27 -08004900
4901 if ((s = lookup_env_parameter("ddr_dimmx_params")) != NULL) {
4902 lmc_dimmx_params.u = strtoul(s, NULL, 0);
4903 }
4904
David Hendricks7d48ac52018-03-09 14:30:38 -08004905 for (i=0; i<16; ++i) {
4906 uint64_t value;
4907 if ((s = lookup_env_parameter("ddr_rc%d", i)) != NULL) {
4908 value = strtoul(s, NULL, 0);
4909 lmc_dimmx_params.u &= ~((uint64_t)0xf << (i*4));
4910 lmc_dimmx_params.u |= ( value << (i*4));
4911 }
4912 }
David Hendricks2004b932018-03-09 13:58:27 -08004913
David Hendricks7d48ac52018-03-09 14:30:38 -08004914 DRAM_CSR_WRITE(node, BDK_LMCX_DIMMX_PARAMS(ddr_interface_num, dimm), lmc_dimmx_params.u);
David Hendricks2004b932018-03-09 13:58:27 -08004915
David Hendricks7d48ac52018-03-09 14:30:38 -08004916 ddr_print("DIMM%d Register Control Words RC15:RC0 : %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
4917 dimm,
4918 lmc_dimmx_params.s.rc15,
4919 lmc_dimmx_params.s.rc14,
4920 lmc_dimmx_params.s.rc13,
4921 lmc_dimmx_params.s.rc12,
4922 lmc_dimmx_params.s.rc11,
4923 lmc_dimmx_params.s.rc10,
4924 lmc_dimmx_params.s.rc9 ,
4925 lmc_dimmx_params.s.rc8 ,
4926 lmc_dimmx_params.s.rc7 ,
4927 lmc_dimmx_params.s.rc6 ,
4928 lmc_dimmx_params.s.rc5 ,
4929 lmc_dimmx_params.s.rc4 ,
4930 lmc_dimmx_params.s.rc3 ,
4931 lmc_dimmx_params.s.rc2 ,
4932 lmc_dimmx_params.s.rc1 ,
4933 lmc_dimmx_params.s.rc0 );
4934 } /* for didx */
David Hendricks2004b932018-03-09 13:58:27 -08004935
David Hendricks7d48ac52018-03-09 14:30:38 -08004936 if (ddr_type == DDR4_DRAM) {
David Hendricks2004b932018-03-09 13:58:27 -08004937
David Hendricks7d48ac52018-03-09 14:30:38 -08004938 /* LMC0_DIMM_CTL */
4939 lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
4940 lmc_dimm_ctl.s.dimm0_wmask = 0xdf3f;
4941 lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xdf3f : 0x0000;
4942 lmc_dimm_ctl.s.tcws = 0x4e0;
4943 lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
David Hendricks2004b932018-03-09 13:58:27 -08004944
David Hendricks7d48ac52018-03-09 14:30:38 -08004945 if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
4946 lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
4947 }
David Hendricks2004b932018-03-09 13:58:27 -08004948
David Hendricks7d48ac52018-03-09 14:30:38 -08004949 if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
4950 lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
4951 }
David Hendricks2004b932018-03-09 13:58:27 -08004952
David Hendricks7d48ac52018-03-09 14:30:38 -08004953 if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
4954 lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
4955 }
David Hendricks2004b932018-03-09 13:58:27 -08004956
David Hendricks7d48ac52018-03-09 14:30:38 -08004957 if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
4958 lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
4959 }
David Hendricks2004b932018-03-09 13:58:27 -08004960
David Hendricks7d48ac52018-03-09 14:30:38 -08004961 ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
4962 DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08004963
David Hendricks7d48ac52018-03-09 14:30:38 -08004964 perform_octeon3_ddr3_sequence(node, rank_mask,
4965 ddr_interface_num, 0x7 ); /* Init RCW */
David Hendricks2004b932018-03-09 13:58:27 -08004966
David Hendricks7d48ac52018-03-09 14:30:38 -08004967 /* Write RC0D last */
4968 lmc_dimm_ctl.s.dimm0_wmask = 0x2000;
4969 lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0x2000 : 0x0000;
4970 ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
4971 DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08004972
David Hendricks7d48ac52018-03-09 14:30:38 -08004973 /* Don't write any extended registers the second time */
4974 DRAM_CSR_WRITE(node, BDK_LMCX_DDR4_DIMM_CTL(ddr_interface_num), 0);
David Hendricks2004b932018-03-09 13:58:27 -08004975
David Hendricks7d48ac52018-03-09 14:30:38 -08004976 perform_octeon3_ddr3_sequence(node, rank_mask,
4977 ddr_interface_num, 0x7 ); /* Init RCW */
David Hendricks2004b932018-03-09 13:58:27 -08004978 } else {
4979
David Hendricks7d48ac52018-03-09 14:30:38 -08004980 /* LMC0_DIMM_CTL */
4981 lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
4982 lmc_dimm_ctl.s.dimm0_wmask = 0xffff;
4983 lmc_dimm_ctl.s.dimm1_wmask = (dimm_count > 1) ? 0xffff : 0x0000;
4984 lmc_dimm_ctl.s.tcws = 0x4e0;
4985 lmc_dimm_ctl.cn88xx.parity = custom_lmc_config->parity;
David Hendricks2004b932018-03-09 13:58:27 -08004986
David Hendricks7d48ac52018-03-09 14:30:38 -08004987 if ((s = lookup_env_parameter("ddr_dimm0_wmask")) != NULL) {
4988 lmc_dimm_ctl.s.dimm0_wmask = strtoul(s, NULL, 0);
4989 }
David Hendricks2004b932018-03-09 13:58:27 -08004990
David Hendricks7d48ac52018-03-09 14:30:38 -08004991 if ((s = lookup_env_parameter("ddr_dimm1_wmask")) != NULL) {
4992 lmc_dimm_ctl.s.dimm1_wmask = strtoul(s, NULL, 0);
4993 }
David Hendricks2004b932018-03-09 13:58:27 -08004994
David Hendricks7d48ac52018-03-09 14:30:38 -08004995 if ((s = lookup_env_parameter("ddr_dimm_ctl_parity")) != NULL) {
4996 lmc_dimm_ctl.cn88xx.parity = strtoul(s, NULL, 0);
4997 }
David Hendricks2004b932018-03-09 13:58:27 -08004998
David Hendricks7d48ac52018-03-09 14:30:38 -08004999 if ((s = lookup_env_parameter("ddr_dimm_ctl_tcws")) != NULL) {
5000 lmc_dimm_ctl.s.tcws = strtoul(s, NULL, 0);
5001 }
David Hendricks2004b932018-03-09 13:58:27 -08005002
David Hendricks7d48ac52018-03-09 14:30:38 -08005003 ddr_print("LMC DIMM_CTL : 0x%016llx\n", lmc_dimm_ctl.u);
5004 DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08005005
David Hendricks7d48ac52018-03-09 14:30:38 -08005006 perform_octeon3_ddr3_sequence(node, rank_mask,
5007 ddr_interface_num, 0x7 ); /* Init RCW */
5008 }
David Hendricks2004b932018-03-09 13:58:27 -08005009 } else { /* if (spd_rdimm) */
5010 /* Disable register control writes for unbuffered */
5011 bdk_lmcx_dimm_ctl_t lmc_dimm_ctl;
5012 lmc_dimm_ctl.u = BDK_CSR_READ(node, BDK_LMCX_DIMM_CTL(ddr_interface_num));
5013 lmc_dimm_ctl.s.dimm0_wmask = 0;
5014 lmc_dimm_ctl.s.dimm1_wmask = 0;
5015 DRAM_CSR_WRITE(node, BDK_LMCX_DIMM_CTL(ddr_interface_num), lmc_dimm_ctl.u);
5016 } /* if (spd_rdimm) */
5017
5018 /*
5019 * Comments (steps 3 through 5) continue in perform_octeon3_ddr3_sequence()
5020 */
5021 {
5022 bdk_lmcx_modereg_params0_t lmc_modereg_params0;
5023
5024 if (ddr_memory_preserved(node)) {
5025 /* Contents are being preserved. Take DRAM out of
5026 self-refresh first. Then init steps can procede
5027 normally */
5028 perform_octeon3_ddr3_sequence(node, rank_mask,
5029 ddr_interface_num, 3); /* self-refresh exit */
5030 }
5031
5032 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
5033
5034 lmc_modereg_params0.s.dllr = 1; /* Set during first init sequence */
5035 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
5036
5037 perform_ddr_init_sequence(node, rank_mask, ddr_interface_num);
5038
5039 lmc_modereg_params0.s.dllr = 0; /* Clear for normal operation */
5040 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
5041 }
5042
5043 // NOTE: this must be done for pass 2.x and pass 1.x
5044 if ((spd_rdimm) && (ddr_type == DDR4_DRAM)) {
5045 VB_PRT(VBL_FAE, "Running init sequence 1\n");
5046 change_rdimm_mpr_pattern(node, rank_mask, ddr_interface_num, dimm_count);
5047 }
5048
5049#define DEFAULT_INTERNAL_VREF_TRAINING_LIMIT 5
5050 int internal_retries = 0;
5051 int deskew_training_errors;
5052 int dac_eval_retries;
5053 int dac_settings[9];
5054 int num_samples;
5055 int sample, lane;
5056 int last_lane = ((ddr_interface_64b) ? 8 : 4) + use_ecc;
5057
5058#define DEFAULT_DAC_SAMPLES 7 // originally was 5
5059#define DAC_RETRIES_LIMIT 2
5060
5061 typedef struct {
5062 int16_t bytes[DEFAULT_DAC_SAMPLES];
5063 } bytelane_sample_t;
5064 bytelane_sample_t lanes[9];
5065
5066 memset(lanes, 0, sizeof(lanes));
5067
5068 if ((ddr_type == DDR4_DRAM) && !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) {
5069 num_samples = DEFAULT_DAC_SAMPLES;
5070 } else {
5071 num_samples = 1; // if DDR3 or no ability to write DAC values
5072 }
5073
5074 perform_internal_vref_training:
5075
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005076 for (sample = 0; sample < num_samples; sample++) {
David Hendricks2004b932018-03-09 13:58:27 -08005077
5078 dac_eval_retries = 0;
5079
5080 do { // make offset and internal vref training repeatable
5081
5082 /* 6.9.8 LMC Offset Training
5083 LMC requires input-receiver offset training. */
5084 Perform_Offset_Training(node, rank_mask, ddr_interface_num);
5085
5086 /* 6.9.9 LMC Internal Vref Training
5087 LMC requires input-reference-voltage training. */
5088 Perform_Internal_VREF_Training(node, rank_mask, ddr_interface_num);
5089
5090 // read and maybe display the DAC values for a sample
5091 read_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, dac_settings);
5092 if ((num_samples == 1) || dram_is_verbose(VBL_DEV)) {
5093 display_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, use_ecc,
David Hendricks7d48ac52018-03-09 14:30:38 -08005094 dac_settings, (char *)"Internal VREF");
David Hendricks2004b932018-03-09 13:58:27 -08005095 }
5096
5097 // for DDR4, evaluate the DAC settings and retry if any issues
5098 if (ddr_type == DDR4_DRAM) {
5099 if (evaluate_DAC_settings(ddr_interface_64b, use_ecc, dac_settings)) {
5100 if (++dac_eval_retries > DAC_RETRIES_LIMIT) {
5101 ddr_print("N%d.LMC%d: DDR4 internal VREF DAC settings: retries exhausted; continuing...\n",
5102 node, ddr_interface_num);
5103 } else {
5104 ddr_print("N%d.LMC%d: DDR4 internal VREF DAC settings inconsistent; retrying....\n",
5105 node, ddr_interface_num); // FIXME? verbosity!!!
5106 continue;
5107 }
5108 }
5109 if (num_samples > 1) { // taking multiple samples, otherwise do nothing
5110 // good sample or exhausted retries, record it
5111 for (lane = 0; lane < last_lane; lane++) {
5112 lanes[lane].bytes[sample] = dac_settings[lane];
5113 }
5114 }
5115 }
5116 break; // done if DDR3, or good sample, or exhausted retries
5117
5118 } while (1);
5119
5120 } /* for (sample = 0; sample < num_samples; sample++) */
5121
5122 if (num_samples > 1) {
5123 debug_print("N%d.LMC%d: DDR4 internal VREF DAC settings: processing multiple samples...\n",
5124 node, ddr_interface_num);
5125
5126 for (lane = 0; lane < last_lane; lane++) {
5127 dac_settings[lane] = process_samples_average(&lanes[lane].bytes[0], num_samples,
5128 ddr_interface_num, lane);
5129 }
David Hendricks7d48ac52018-03-09 14:30:38 -08005130 display_DAC_DBI_settings(node, ddr_interface_num, /*DAC*/1, use_ecc, dac_settings, (char *)"Averaged VREF");
David Hendricks2004b932018-03-09 13:58:27 -08005131
5132 // finally, write the final DAC values
5133 for (lane = 0; lane < last_lane; lane++) {
5134 load_dac_override(node, ddr_interface_num, dac_settings[lane], lane);
5135 }
5136 }
5137
5138#if DAC_OVERRIDE_EARLY
5139 // as a second step, after internal VREF training, before starting deskew training:
5140 // for DDR3 and THUNDER pass 2.x, override the DAC setting to 127
5141 if ((ddr_type == DDR3_DRAM) && !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
5142 load_dac_override(node, ddr_interface_num, 127, /* all */0x0A);
5143 ddr_print("N%d.LMC%d: Overriding DDR3 internal VREF DAC settings to 127 (early).\n",
5144 node, ddr_interface_num);
5145 }
5146#endif
5147
5148 /*
5149 * 6.9.10 LMC Read Deskew Training
5150 * LMC requires input-read-data deskew training.
5151 */
5152 if (! disable_deskew_training) {
5153
5154 deskew_training_errors = Perform_Read_Deskew_Training(node, rank_mask, ddr_interface_num,
5155 spd_rawcard_AorB, 0, ddr_interface_64b);
5156
5157 // All the Deskew lock and saturation retries (may) have been done,
5158 // but we ended up with nibble errors; so, as a last ditch effort,
5159 // enable retries of the Internal Vref Training...
5160 if (deskew_training_errors) {
5161 if (internal_retries < DEFAULT_INTERNAL_VREF_TRAINING_LIMIT) {
5162 internal_retries++;
5163 VB_PRT(VBL_FAE, "N%d.LMC%d: Deskew training results still unsettled - retrying internal Vref training (%d)\n",
5164 node, ddr_interface_num, internal_retries);
5165 goto perform_internal_vref_training;
5166 } else {
5167 VB_PRT(VBL_FAE, "N%d.LMC%d: Deskew training incomplete - %d retries exhausted, but continuing...\n",
5168 node, ddr_interface_num, internal_retries);
5169 }
5170 }
5171
5172 // FIXME: treat this as the final DSK print from now on, and print if VBL_NORM or above
5173 // also, save the results of the original training
5174 Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &deskew_training_results, VBL_NORM);
5175
5176 // setup write bit-deskew if enabled...
5177 if (enable_write_deskew) {
5178 ddr_print("N%d.LMC%d: WRITE BIT-DESKEW feature enabled- going NEUTRAL.\n",
5179 node, ddr_interface_num);
5180 Neutral_Write_Deskew_Setup(node, ddr_interface_num);
5181 } /* if (enable_write_deskew) */
5182
5183 } /* if (! disable_deskew_training) */
5184
5185#if !DAC_OVERRIDE_EARLY
5186 // as a final step in internal VREF training, after deskew training but before HW WL:
5187 // for DDR3 and THUNDER pass 2.x, override the DAC setting to 127
5188 if ((ddr_type == DDR3_DRAM) && !CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X)) { // added 81xx and 83xx
5189 load_dac_override(node, ddr_interface_num, 127, /* all */0x0A);
5190 ddr_print("N%d.LMC%d, Overriding DDR3 internal VREF DAC settings to 127 (late).\n",
5191 node, ddr_interface_num);
5192 }
5193#endif
5194
5195
5196 /* LMC(0)_EXT_CONFIG */
5197 {
5198 bdk_lmcx_ext_config_t ext_config;
5199 ext_config.u = BDK_CSR_READ(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num));
5200 ext_config.s.vrefint_seq_deskew = 0;
5201 ext_config.s.read_ena_bprch = 1;
5202 ext_config.s.read_ena_fprch = 1;
5203 ext_config.s.drive_ena_fprch = 1;
5204 ext_config.s.drive_ena_bprch = 1;
5205 ext_config.s.invert_data = 0; // make sure this is OFF for all current chips
5206
5207 if ((s = lookup_env_parameter("ddr_read_fprch")) != NULL) {
5208 ext_config.s.read_ena_fprch = strtoul(s, NULL, 0);
5209 }
5210 if ((s = lookup_env_parameter("ddr_read_bprch")) != NULL) {
5211 ext_config.s.read_ena_bprch = strtoul(s, NULL, 0);
5212 }
5213 if ((s = lookup_env_parameter("ddr_drive_fprch")) != NULL) {
5214 ext_config.s.drive_ena_fprch = strtoul(s, NULL, 0);
5215 }
5216 if ((s = lookup_env_parameter("ddr_drive_bprch")) != NULL) {
5217 ext_config.s.drive_ena_bprch = strtoul(s, NULL, 0);
5218 }
5219
5220 if (!CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (lranks_per_prank > 1)) {
5221 ext_config.s.dimm0_cid = ext_config.s.dimm1_cid = lranks_bits;
5222 ddr_print("N%d.LMC%d: 3DS: setting EXT_CONFIG[dimmx_cid] = %d\n",
5223 node, ddr_interface_num, ext_config.s.dimm0_cid);
5224 }
5225
5226 DRAM_CSR_WRITE(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num), ext_config.u);
David Hendricks7d48ac52018-03-09 14:30:38 -08005227 ddr_print("%-45s : 0x%016llx\n", "EXT_CONFIG", ext_config.u);
David Hendricks2004b932018-03-09 13:58:27 -08005228 }
5229
5230
5231 {
5232 int save_ref_zqcs_int;
5233 uint64_t temp_delay_usecs;
5234
5235 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5236
5237 /* Temporarily select the minimum ZQCS interval and wait
5238 long enough for a few ZQCS calibrations to occur. This
5239 should ensure that the calibration circuitry is
5240 stabilized before read/write leveling occurs. */
David Hendricks7d48ac52018-03-09 14:30:38 -08005241 save_ref_zqcs_int = lmc_config.s.ref_zqcs_int;
5242 lmc_config.s.ref_zqcs_int = 1 | (32<<7); /* set smallest interval */
David Hendricks2004b932018-03-09 13:58:27 -08005243
5244 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
5245 BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5246
5247 /* Compute an appropriate delay based on the current ZQCS
5248 interval. The delay should be long enough for the
5249 current ZQCS delay counter to expire plus ten of the
5250 minimum intarvals to ensure that some calibrations
5251 occur. */
5252 temp_delay_usecs = (((uint64_t)save_ref_zqcs_int >> 7)
5253 * tclk_psecs * 100 * 512 * 128) / (10000*10000)
5254 + 10 * ((uint64_t)32 * tclk_psecs * 100 * 512 * 128) / (10000*10000);
5255
David Hendricks7d48ac52018-03-09 14:30:38 -08005256 VB_PRT(VBL_FAE, "N%d.LMC%d: Waiting %lld usecs for ZQCS calibrations to start\n",
David Hendricks2004b932018-03-09 13:58:27 -08005257 node, ddr_interface_num, temp_delay_usecs);
5258 bdk_wait_usec(temp_delay_usecs);
5259
David Hendricks7d48ac52018-03-09 14:30:38 -08005260 lmc_config.s.ref_zqcs_int = save_ref_zqcs_int; /* Restore computed interval */
David Hendricks2004b932018-03-09 13:58:27 -08005261
5262 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
5263 BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5264 }
5265
5266 /*
5267 * 6.9.11 LMC Write Leveling
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005268 *
David Hendricks2004b932018-03-09 13:58:27 -08005269 * LMC supports an automatic write leveling like that described in the
5270 * JEDEC DDR3 specifications separately per byte-lane.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005271 *
David Hendricks2004b932018-03-09 13:58:27 -08005272 * All of DDR PLL, LMC CK, LMC DRESET, and early LMC initializations must
5273 * be completed prior to starting this LMC write-leveling sequence.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005274 *
David Hendricks2004b932018-03-09 13:58:27 -08005275 * There are many possible procedures that will write-level all the
5276 * attached DDR3 DRAM parts. One possibility is for software to simply
5277 * write the desired values into LMC(0)_WLEVEL_RANK(0..3). This section
5278 * describes one possible sequence that uses LMC's autowrite-leveling
5279 * capabilities.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005280 *
David Hendricks2004b932018-03-09 13:58:27 -08005281 * 1. If the DQS/DQ delays on the board may be more than the ADD/CMD
5282 * delays, then ensure that LMC(0)_CONFIG[EARLY_DQX] is set at this
5283 * point.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005284 *
David Hendricks2004b932018-03-09 13:58:27 -08005285 * Do the remaining steps 2-7 separately for each rank i with attached
5286 * DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005287 *
David Hendricks2004b932018-03-09 13:58:27 -08005288 * 2. Write LMC(0)_WLEVEL_RANKi = 0.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005289 *
David Hendricks2004b932018-03-09 13:58:27 -08005290 * 3. For ×8 parts:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005291 *
David Hendricks2004b932018-03-09 13:58:27 -08005292 * Without changing any other fields in LMC(0)_WLEVEL_CTL, write
5293 * LMC(0)_WLEVEL_CTL[LANEMASK] to select all byte lanes with attached
5294 * DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005295 *
David Hendricks2004b932018-03-09 13:58:27 -08005296 * For ×16 parts:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005297 *
David Hendricks2004b932018-03-09 13:58:27 -08005298 * Without changing any other fields in LMC(0)_WLEVEL_CTL, write
5299 * LMC(0)_WLEVEL_CTL[LANEMASK] to select all even byte lanes with
5300 * attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005301 *
David Hendricks2004b932018-03-09 13:58:27 -08005302 * 4. Without changing any other fields in LMC(0)_CONFIG,
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005303 *
David Hendricks2004b932018-03-09 13:58:27 -08005304 * o write LMC(0)_SEQ_CTL[SEQ_SEL] to select write-leveling
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005305 *
David Hendricks2004b932018-03-09 13:58:27 -08005306 * o write LMC(0)_CONFIG[RANKMASK] = (1 << i)
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005307 *
David Hendricks2004b932018-03-09 13:58:27 -08005308 * o write LMC(0)_SEQ_CTL[INIT_START] = 1
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005309 *
David Hendricks2004b932018-03-09 13:58:27 -08005310 * LMC will initiate write-leveling at this point. Assuming
5311 * LMC(0)_WLEVEL_CTL [SSET] = 0, LMC first enables write-leveling on
5312 * the selected DRAM rank via a DDR3 MR1 write, then sequences through
5313 * and accumulates write-leveling results for eight different delay
5314 * settings twice, starting at a delay of zero in this case since
5315 * LMC(0)_WLEVEL_RANKi[BYTE*<4:3>] = 0, increasing by 1/8 CK each
5316 * setting, covering a total distance of one CK, then disables the
5317 * write-leveling via another DDR3 MR1 write.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005318 *
David Hendricks2004b932018-03-09 13:58:27 -08005319 * After the sequence through 16 delay settings is complete:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005320 *
David Hendricks2004b932018-03-09 13:58:27 -08005321 * o LMC sets LMC(0)_WLEVEL_RANKi[STATUS] = 3
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005322 *
David Hendricks2004b932018-03-09 13:58:27 -08005323 * o LMC sets LMC(0)_WLEVEL_RANKi[BYTE*<2:0>] (for all ranks selected
5324 * by LMC(0)_WLEVEL_CTL[LANEMASK]) to indicate the first write
5325 * leveling result of 1 that followed result of 0 during the
5326 * sequence, except that the LMC always writes
5327 * LMC(0)_WLEVEL_RANKi[BYTE*<0>]=0.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005328 *
David Hendricks2004b932018-03-09 13:58:27 -08005329 * o Software can read the eight write-leveling results from the first
5330 * pass through the delay settings by reading
5331 * LMC(0)_WLEVEL_DBG[BITMASK] (after writing
5332 * LMC(0)_WLEVEL_DBG[BYTE]). (LMC does not retain the writeleveling
5333 * results from the second pass through the eight delay
5334 * settings. They should often be identical to the
5335 * LMC(0)_WLEVEL_DBG[BITMASK] results, though.)
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005336 *
David Hendricks2004b932018-03-09 13:58:27 -08005337 * 5. Wait until LMC(0)_WLEVEL_RANKi[STATUS] != 2.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005338 *
David Hendricks2004b932018-03-09 13:58:27 -08005339 * LMC will have updated LMC(0)_WLEVEL_RANKi[BYTE*<2:0>] for all byte
5340 * lanes selected by LMC(0)_WLEVEL_CTL[LANEMASK] at this point.
5341 * LMC(0)_WLEVEL_RANKi[BYTE*<4:3>] will still be the value that
5342 * software wrote in substep 2 above, which is 0.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005343 *
David Hendricks2004b932018-03-09 13:58:27 -08005344 * 6. For ×16 parts:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005345 *
David Hendricks2004b932018-03-09 13:58:27 -08005346 * Without changing any other fields in LMC(0)_WLEVEL_CTL, write
5347 * LMC(0)_WLEVEL_CTL[LANEMASK] to select all odd byte lanes with
5348 * attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005349 *
David Hendricks2004b932018-03-09 13:58:27 -08005350 * Repeat substeps 4 and 5 with this new LMC(0)_WLEVEL_CTL[LANEMASK]
5351 * setting. Skip to substep 7 if this has already been done.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005352 *
David Hendricks2004b932018-03-09 13:58:27 -08005353 * For ×8 parts:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005354 *
David Hendricks2004b932018-03-09 13:58:27 -08005355 * Skip this substep. Go to substep 7.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005356 *
David Hendricks2004b932018-03-09 13:58:27 -08005357 * 7. Calculate LMC(0)_WLEVEL_RANKi[BYTE*<4:3>] settings for all byte
5358 * lanes on all ranks with attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005359 *
David Hendricks2004b932018-03-09 13:58:27 -08005360 * At this point, all byte lanes on rank i with attached DRAM should
5361 * have been write-leveled, and LMC(0)_WLEVEL_RANKi[BYTE*<2:0>] has
5362 * the result for each byte lane.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005363 *
David Hendricks2004b932018-03-09 13:58:27 -08005364 * But note that the DDR3 write-leveling sequence will only determine
5365 * the delay modulo the CK cycle time, and cannot determine how many
5366 * additional CK cycles of delay are present. Software must calculate
5367 * the number of CK cycles, or equivalently, the
5368 * LMC(0)_WLEVEL_RANKi[BYTE*<4:3>] settings.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005369 *
David Hendricks2004b932018-03-09 13:58:27 -08005370 * This BYTE*<4:3> calculation is system/board specific.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005371 *
David Hendricks2004b932018-03-09 13:58:27 -08005372 * Many techniques can be used to calculate write-leveling BYTE*<4:3> values,
5373 * including:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005374 *
David Hendricks2004b932018-03-09 13:58:27 -08005375 * o Known values for some byte lanes.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005376 *
David Hendricks2004b932018-03-09 13:58:27 -08005377 * o Relative values for some byte lanes relative to others.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005378 *
David Hendricks2004b932018-03-09 13:58:27 -08005379 * For example, suppose lane X is likely to require a larger
5380 * write-leveling delay than lane Y. A BYTEX<2:0> value that is much
5381 * smaller than the BYTEY<2:0> value may then indicate that the
5382 * required lane X delay wrapped into the next CK, so BYTEX<4:3>
5383 * should be set to BYTEY<4:3>+1.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005384 *
David Hendricks2004b932018-03-09 13:58:27 -08005385 * When ECC DRAM is not present (i.e. when DRAM is not attached to the
5386 * DDR_CBS_0_* and DDR_CB<7:0> chip signals, or the DDR_DQS_<4>_* and
5387 * DDR_DQ<35:32> chip signals), write LMC(0)_WLEVEL_RANK*[BYTE8] =
5388 * LMC(0)_WLEVEL_RANK*[BYTE0], using the final calculated BYTE0 value.
5389 * Write LMC(0)_WLEVEL_RANK*[BYTE4] = LMC(0)_WLEVEL_RANK*[BYTE0],
5390 * using the final calculated BYTE0 value.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005391 *
David Hendricks2004b932018-03-09 13:58:27 -08005392 * 8. Initialize LMC(0)_WLEVEL_RANK* values for all unused ranks.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005393 *
David Hendricks2004b932018-03-09 13:58:27 -08005394 * Let rank i be a rank with attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005395 *
David Hendricks2004b932018-03-09 13:58:27 -08005396 * For all ranks j that do not have attached DRAM, set
5397 * LMC(0)_WLEVEL_RANKj = LMC(0)_WLEVEL_RANKi.
5398 */
5399 { // Start HW write-leveling block
5400#pragma pack(push,1)
5401 bdk_lmcx_wlevel_ctl_t wlevel_ctl;
5402 bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank;
5403 int rankx = 0;
5404 int wlevel_bitmask[9];
5405 int byte_idx;
5406 int ecc_ena;
5407 int ddr_wlevel_roundup = 0;
5408 int ddr_wlevel_printall = (dram_is_verbose(VBL_FAE)); // or default to 1 to print all HW WL samples
5409 int disable_hwl_validity = 0;
5410 int default_wlevel_rtt_nom;
5411#if WODT_MASK_2R_1S
5412 uint64_t saved_wodt_mask = 0;
5413#endif
5414#pragma pack(pop)
5415
5416 if (wlevel_loops)
5417 ddr_print("N%d.LMC%d: Performing Hardware Write-Leveling\n", node, ddr_interface_num);
5418 else {
5419 wlevel_bitmask_errors = 1; /* Force software write-leveling to run */
5420 ddr_print("N%d.LMC%d: Forcing software Write-Leveling\n", node, ddr_interface_num);
David Hendricks7d48ac52018-03-09 14:30:38 -08005421 }
David Hendricks2004b932018-03-09 13:58:27 -08005422
5423 default_wlevel_rtt_nom = (ddr_type == DDR3_DRAM) ? rttnom_20ohm : ddr4_rttnom_40ohm ; /* FIXME? */
5424
5425#if WODT_MASK_2R_1S
5426 if ((ddr_type == DDR4_DRAM) && (num_ranks == 2) && (dimm_count == 1)) {
5427 /* LMC(0)_WODT_MASK */
5428 bdk_lmcx_wodt_mask_t lmc_wodt_mask;
5429 // always save original so we can always restore later
5430 saved_wodt_mask = BDK_CSR_READ(node, BDK_LMCX_WODT_MASK(ddr_interface_num));
5431 if ((s = lookup_env_parameter_ull("ddr_hwl_wodt_mask")) != NULL) {
5432 lmc_wodt_mask.u = strtoull(s, NULL, 0);
5433 if (lmc_wodt_mask.u != saved_wodt_mask) { // print/store only when diff
David Hendricks7d48ac52018-03-09 14:30:38 -08005434 ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
David Hendricks2004b932018-03-09 13:58:27 -08005435 DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
5436 }
5437 }
5438 }
5439#endif /* WODT_MASK_2R_1S */
5440
5441 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
David Hendricks7d48ac52018-03-09 14:30:38 -08005442 ecc_ena = lmc_config.s.ecc_ena;
David Hendricks2004b932018-03-09 13:58:27 -08005443
David Hendricks7d48ac52018-03-09 14:30:38 -08005444 if ((s = lookup_env_parameter("ddr_wlevel_roundup")) != NULL) {
5445 ddr_wlevel_roundup = strtoul(s, NULL, 0);
5446 }
5447 if ((s = lookup_env_parameter("ddr_wlevel_printall")) != NULL) {
5448 ddr_wlevel_printall = strtoul(s, NULL, 0);
5449 }
David Hendricks2004b932018-03-09 13:58:27 -08005450
David Hendricks7d48ac52018-03-09 14:30:38 -08005451 if ((s = lookup_env_parameter("ddr_disable_hwl_validity")) != NULL) {
5452 disable_hwl_validity = !!strtoul(s, NULL, 0);
5453 }
David Hendricks2004b932018-03-09 13:58:27 -08005454
5455 if ((s = lookup_env_parameter("ddr_wlevel_rtt_nom")) != NULL) {
5456 default_wlevel_rtt_nom = strtoul(s, NULL, 0);
5457 }
5458
5459 // For DDR3, we leave the WLEVEL_CTL fields at default settings
5460 // For DDR4, we touch WLEVEL_CTL fields OR_DIS or BITMASK here
5461 if (ddr_type == DDR4_DRAM) {
5462 int default_or_dis = 1;
5463 int default_bitmask = 0xFF;
5464
5465 // when x4, use only the lower nibble bits
5466 if (dram_width == 4) {
5467 default_bitmask = 0x0F;
5468 VB_PRT(VBL_DEV, "N%d.LMC%d: WLEVEL_CTL: default bitmask is 0x%2x for DDR4 x4\n",
5469 node, ddr_interface_num, default_bitmask);
5470 }
5471
5472 wlevel_ctl.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num));
5473 wlevel_ctl.s.or_dis = default_or_dis;
5474 wlevel_ctl.s.bitmask = default_bitmask;
5475
5476 // allow overrides
5477 if ((s = lookup_env_parameter("ddr_wlevel_ctl_or_dis")) != NULL) {
5478 wlevel_ctl.s.or_dis = !!strtoul(s, NULL, 0);
5479 }
5480 if ((s = lookup_env_parameter("ddr_wlevel_ctl_bitmask")) != NULL) {
5481 wlevel_ctl.s.bitmask = strtoul(s, NULL, 0);
5482 }
5483
5484 // print only if not defaults
5485 if ((wlevel_ctl.s.or_dis != default_or_dis) || (wlevel_ctl.s.bitmask != default_bitmask)) {
5486 ddr_print("N%d.LMC%d: WLEVEL_CTL: or_dis=%d, bitmask=0x%02x\n",
5487 node, ddr_interface_num, wlevel_ctl.s.or_dis, wlevel_ctl.s.bitmask);
5488 }
5489 // always write
5490 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
5491 }
5492
5493 // Start the hardware write-leveling loop per rank
David Hendricks7d48ac52018-03-09 14:30:38 -08005494 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
David Hendricks2004b932018-03-09 13:58:27 -08005495
David Hendricks7d48ac52018-03-09 14:30:38 -08005496 if (!(rank_mask & (1 << rankx)))
5497 continue;
David Hendricks2004b932018-03-09 13:58:27 -08005498
5499#if HW_WL_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08005500 // array to collect counts of byte-lane values
5501 // assume low-order 3 bits and even, so really only 2 bit values
5502 int wlevel_bytes[9][4];
5503 memset(wlevel_bytes, 0, sizeof(wlevel_bytes));
David Hendricks2004b932018-03-09 13:58:27 -08005504#endif
5505
David Hendricks7d48ac52018-03-09 14:30:38 -08005506 // restructure the looping so we can keep trying until we get the samples we want
5507 //for (int wloop = 0; wloop < wlevel_loops; wloop++) {
5508 int wloop = 0;
5509 int wloop_retries = 0; // retries per sample for HW-related issues with bitmasks or values
David Hendricks2004b932018-03-09 13:58:27 -08005510 int wloop_retries_total = 0;
5511 int wloop_retries_exhausted = 0;
5512#define WLOOP_RETRIES_DEFAULT 5
5513 int wlevel_validity_errors;
5514 int wlevel_bitmask_errors_rank = 0;
5515 int wlevel_validity_errors_rank = 0;
5516
David Hendricks7d48ac52018-03-09 14:30:38 -08005517 while (wloop < wlevel_loops) {
David Hendricks2004b932018-03-09 13:58:27 -08005518
David Hendricks7d48ac52018-03-09 14:30:38 -08005519 wlevel_ctl.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08005520
David Hendricks7d48ac52018-03-09 14:30:38 -08005521 wlevel_ctl.s.rtt_nom = (default_wlevel_rtt_nom > 0) ? (default_wlevel_rtt_nom - 1) : 7;
David Hendricks2004b932018-03-09 13:58:27 -08005522
5523
David Hendricks7d48ac52018-03-09 14:30:38 -08005524 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), 0); /* Clear write-level delays */
David Hendricks2004b932018-03-09 13:58:27 -08005525
David Hendricks7d48ac52018-03-09 14:30:38 -08005526 wlevel_bitmask_errors = 0; /* Reset error counters */
David Hendricks2004b932018-03-09 13:58:27 -08005527 wlevel_validity_errors = 0;
5528
David Hendricks7d48ac52018-03-09 14:30:38 -08005529 for (byte_idx=0; byte_idx<9; ++byte_idx) {
5530 wlevel_bitmask[byte_idx] = 0; /* Reset bitmasks */
5531 }
David Hendricks2004b932018-03-09 13:58:27 -08005532
5533#if HWL_BY_BYTE // FIXME???
David Hendricks7d48ac52018-03-09 14:30:38 -08005534 /* Make a separate pass for each byte to reduce power. */
5535 for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
David Hendricks2004b932018-03-09 13:58:27 -08005536
David Hendricks7d48ac52018-03-09 14:30:38 -08005537 if (!(ddr_interface_bytemask&(1<<byte_idx)))
5538 continue;
David Hendricks2004b932018-03-09 13:58:27 -08005539
David Hendricks7d48ac52018-03-09 14:30:38 -08005540 wlevel_ctl.s.lanemask = (1<<byte_idx);
David Hendricks2004b932018-03-09 13:58:27 -08005541
David Hendricks7d48ac52018-03-09 14:30:38 -08005542 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08005543
David Hendricks7d48ac52018-03-09 14:30:38 -08005544 /* Read and write values back in order to update the
5545 status field. This insures that we read the updated
5546 values after write-leveling has completed. */
5547 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
5548 BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
David Hendricks2004b932018-03-09 13:58:27 -08005549
David Hendricks7d48ac52018-03-09 14:30:38 -08005550 perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
David Hendricks2004b932018-03-09 13:58:27 -08005551
David Hendricks7d48ac52018-03-09 14:30:38 -08005552 if (!bdk_is_platform(BDK_PLATFORM_ASIM) &&
5553 BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
5554 status, ==, 3, 1000000))
5555 {
5556 error_print("ERROR: Timeout waiting for WLEVEL\n");
5557 }
5558 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08005559
David Hendricks7d48ac52018-03-09 14:30:38 -08005560 wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
5561 if (wlevel_bitmask[byte_idx] == 0)
5562 ++wlevel_bitmask_errors;
5563 } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08005564
David Hendricks7d48ac52018-03-09 14:30:38 -08005565 wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // restore for RL
5566 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08005567#else
5568 // do all the byte-lanes at the same time
David Hendricks7d48ac52018-03-09 14:30:38 -08005569 wlevel_ctl.s.lanemask = /*0x1ff*/ddr_interface_bytemask; // FIXME?
David Hendricks2004b932018-03-09 13:58:27 -08005570
David Hendricks7d48ac52018-03-09 14:30:38 -08005571 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_CTL(ddr_interface_num), wlevel_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08005572
David Hendricks7d48ac52018-03-09 14:30:38 -08005573 /* Read and write values back in order to update the
5574 status field. This insures that we read the updated
5575 values after write-leveling has completed. */
5576 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
5577 BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx)));
David Hendricks2004b932018-03-09 13:58:27 -08005578
David Hendricks7d48ac52018-03-09 14:30:38 -08005579 perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 6); /* write-leveling */
David Hendricks2004b932018-03-09 13:58:27 -08005580
David Hendricks7d48ac52018-03-09 14:30:38 -08005581 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx),
5582 status, ==, 3, 1000000))
5583 {
5584 error_print("ERROR: Timeout waiting for WLEVEL\n");
5585 }
David Hendricks2004b932018-03-09 13:58:27 -08005586
David Hendricks7d48ac52018-03-09 14:30:38 -08005587 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08005588
David Hendricks7d48ac52018-03-09 14:30:38 -08005589 for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
5590 if (!(ddr_interface_bytemask&(1<<byte_idx)))
5591 continue;
5592 wlevel_bitmask[byte_idx] = octeon_read_lmcx_ddr3_wlevel_dbg(node, ddr_interface_num, byte_idx);
5593 if (wlevel_bitmask[byte_idx] == 0)
5594 ++wlevel_bitmask_errors;
5595 } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08005596#endif
5597
5598 // check validity only if no bitmask errors
5599 if (wlevel_bitmask_errors == 0) {
5600 if ((spd_dimm_type != 5) &&
5601 (spd_dimm_type != 6) &&
5602 (spd_dimm_type != 8) &&
5603 (spd_dimm_type != 9) &&
5604 (dram_width != 16) &&
5605 (ddr_interface_64b) &&
5606 !(disable_hwl_validity))
5607 { // bypass if mini-[RU]DIMM or x16 or 32-bit or SO-[RU]DIMM
5608 wlevel_validity_errors =
5609 Validate_HW_WL_Settings(node, ddr_interface_num,
5610 &lmc_wlevel_rank, ecc_ena);
5611 wlevel_validity_errors_rank += (wlevel_validity_errors != 0);
5612 }
5613 } else
5614 wlevel_bitmask_errors_rank++;
5615
David Hendricks7d48ac52018-03-09 14:30:38 -08005616 // before we print, if we had bitmask or validity errors, do a retry...
5617 if ((wlevel_bitmask_errors != 0) || (wlevel_validity_errors != 0)) {
David Hendricks2004b932018-03-09 13:58:27 -08005618 // VBL must be high to show the bad bitmaps or delays here also
5619 if (dram_is_verbose(VBL_DEV2)) {
5620 display_WL_BM(node, ddr_interface_num, rankx, wlevel_bitmask);
5621 display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
5622 }
David Hendricks7d48ac52018-03-09 14:30:38 -08005623 if (wloop_retries < WLOOP_RETRIES_DEFAULT) {
5624 wloop_retries++;
David Hendricks2004b932018-03-09 13:58:27 -08005625 wloop_retries_total++;
David Hendricks7d48ac52018-03-09 14:30:38 -08005626 // this printout is per-retry: only when VBL is high enough (DEV2?)
5627 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling had %s errors - retrying...\n",
5628 node, ddr_interface_num, rankx,
David Hendricks2004b932018-03-09 13:58:27 -08005629 (wlevel_bitmask_errors) ? "Bitmask" : "Validity");
David Hendricks7d48ac52018-03-09 14:30:38 -08005630 continue; // this takes us back to the top without counting a sample
5631 } else { // ran out of retries for this sample
David Hendricks2004b932018-03-09 13:58:27 -08005632 // retries exhausted, do not print at normal VBL
David Hendricks7d48ac52018-03-09 14:30:38 -08005633 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: H/W Write-Leveling issues: %s errors\n",
5634 node, ddr_interface_num, rankx,
David Hendricks2004b932018-03-09 13:58:27 -08005635 (wlevel_bitmask_errors) ? "Bitmask" : "Validity");
5636 wloop_retries_exhausted++;
David Hendricks7d48ac52018-03-09 14:30:38 -08005637 }
5638 }
David Hendricks2004b932018-03-09 13:58:27 -08005639 // no errors or exhausted retries, use this sample
5640 wloop_retries = 0; //reset for next sample
5641
David Hendricks7d48ac52018-03-09 14:30:38 -08005642 // when only 1 sample or forced, print the bitmasks first and current HW WL
5643 if ((wlevel_loops == 1) || ddr_wlevel_printall) {
5644 display_WL_BM(node, ddr_interface_num, rankx, wlevel_bitmask);
5645 display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
5646 }
David Hendricks2004b932018-03-09 13:58:27 -08005647
David Hendricks7d48ac52018-03-09 14:30:38 -08005648 if (ddr_wlevel_roundup) { /* Round up odd bitmask delays */
5649 for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
5650 if (!(ddr_interface_bytemask&(1<<byte_idx)))
5651 continue;
5652 update_wlevel_rank_struct(&lmc_wlevel_rank,
5653 byte_idx,
5654 roundup_ddr3_wlevel_bitmask(wlevel_bitmask[byte_idx]));
5655 } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
5656 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
5657 display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
5658 }
David Hendricks2004b932018-03-09 13:58:27 -08005659
5660#if HW_WL_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08005661 // OK, we have a decent sample, no bitmask or validity errors
5662 for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) {
5663 if (!(ddr_interface_bytemask&(1<<byte_idx)))
5664 continue;
5665 // increment count of byte-lane value
5666 int ix = (get_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx) >> 1) & 3; // only 4 values
5667 wlevel_bytes[byte_idx][ix]++;
5668 } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08005669#endif
5670
David Hendricks7d48ac52018-03-09 14:30:38 -08005671 wloop++; // if we get here, we have taken a decent sample
David Hendricks2004b932018-03-09 13:58:27 -08005672
David Hendricks7d48ac52018-03-09 14:30:38 -08005673 } /* while (wloop < wlevel_loops) */
David Hendricks2004b932018-03-09 13:58:27 -08005674
5675#if HW_WL_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08005676 // if we did sample more than once, try to pick a majority vote
5677 if (wlevel_loops > 1) {
5678 // look for the majority in each byte-lane
5679 for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
5680 int mx = -1, mc = 0, xc = 0, cc = 0;
5681 int ix, ic;
5682 if (!(ddr_interface_bytemask&(1<<byte_idx)))
5683 continue;
5684 for (ix = 0; ix < 4; ix++) {
5685 ic = wlevel_bytes[byte_idx][ix];
5686 // make a bitmask of the ones with a count
5687 if (ic > 0) {
5688 mc |= (1 << ix);
5689 cc++; // count how many had non-zero counts
5690 }
5691 // find the majority
5692 if (ic > xc) { // new max?
5693 xc = ic; // yes
5694 mx = ix; // set its index
5695 }
5696 }
David Hendricks2004b932018-03-09 13:58:27 -08005697#if SWL_TRY_HWL_ALT
David Hendricks7d48ac52018-03-09 14:30:38 -08005698 // see if there was an alternate
5699 int alts = (mc & ~(1 << mx)); // take out the majority choice
5700 if (alts != 0) {
5701 for (ix = 0; ix < 4; ix++) {
5702 if (alts & (1 << ix)) { // FIXME: could be done multiple times? bad if so
5703 hwl_alts[rankx].hwl_alt_mask |= (1 << byte_idx); // set the mask
5704 hwl_alts[rankx].hwl_alt_delay[byte_idx] = ix << 1; // record the value
5705 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d (%d) alt %d (%d).\n",
David Hendricks2004b932018-03-09 13:58:27 -08005706 node, ddr_interface_num, rankx, byte_idx, mx << 1, xc,
5707 ix << 1, wlevel_bytes[byte_idx][ix]);
David Hendricks7d48ac52018-03-09 14:30:38 -08005708 }
5709 }
5710 } else {
5711 debug_print("N%d.LMC%d.R%d: SWL_TRY_HWL_ALT: Byte %d maj %d alt NONE.\n",
5712 node, ddr_interface_num, rankx, byte_idx, mx << 1);
5713 }
David Hendricks2004b932018-03-09 13:58:27 -08005714#endif /* SWL_TRY_HWL_ALT */
David Hendricks7d48ac52018-03-09 14:30:38 -08005715 if (cc > 2) { // unlikely, but...
5716 // assume: counts for 3 indices are all 1
5717 // possiblities are: 0/2/4, 2/4/6, 0/4/6, 0/2/6
5718 // and the desired?: 2 , 4 , 6, 0
5719 // we choose the middle, assuming one of the outliers is bad
5720 // NOTE: this is an ugly hack at the moment; there must be a better way
5721 switch (mc) {
5722 case 0x7: mx = 1; break; // was 0/2/4, choose 2
5723 case 0xb: mx = 0; break; // was 0/2/6, choose 0
5724 case 0xd: mx = 3; break; // was 0/4/6, choose 6
5725 case 0xe: mx = 2; break; // was 2/4/6, choose 4
5726 default:
5727 case 0xf: mx = 1; break; // was 0/2/4/6, choose 2?
5728 }
5729 error_print("N%d.LMC%d.R%d: HW WL MAJORITY: bad byte-lane %d (0x%x), using %d.\n",
5730 node, ddr_interface_num, rankx, byte_idx, mc, mx << 1);
5731 }
5732 update_wlevel_rank_struct(&lmc_wlevel_rank, byte_idx, mx << 1);
5733 } /* for (byte_idx=0; byte_idx<(8+ecc_ena); ++byte_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08005734
David Hendricks7d48ac52018-03-09 14:30:38 -08005735 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
5736 display_WL_with_final(node, ddr_interface_num, lmc_wlevel_rank, rankx);
5737 } /* if (wlevel_loops > 1) */
David Hendricks2004b932018-03-09 13:58:27 -08005738#endif /* HW_WL_MAJORITY */
5739 // maybe print an error summary for the rank
5740 if ((wlevel_bitmask_errors_rank != 0) || (wlevel_validity_errors_rank != 0)) {
5741 VB_PRT(VBL_FAE, "N%d.LMC%d.R%d: H/W Write-Leveling errors - %d bitmask, %d validity, %d retries, %d exhausted\n",
5742 node, ddr_interface_num, rankx,
5743 wlevel_bitmask_errors_rank, wlevel_validity_errors_rank,
5744 wloop_retries_total, wloop_retries_exhausted);
5745 }
5746
David Hendricks7d48ac52018-03-09 14:30:38 -08005747 } /* for (rankx = 0; rankx < dimm_count * 4;rankx++) */
David Hendricks2004b932018-03-09 13:58:27 -08005748
5749#if WODT_MASK_2R_1S
5750 if ((ddr_type == DDR4_DRAM) && (num_ranks == 2) && (dimm_count == 1)) {
5751 /* LMC(0)_WODT_MASK */
5752 bdk_lmcx_wodt_mask_t lmc_wodt_mask;
5753 // always read current so we can see if its different from saved
5754 lmc_wodt_mask.u = BDK_CSR_READ(node, BDK_LMCX_WODT_MASK(ddr_interface_num));
5755 if (lmc_wodt_mask.u != saved_wodt_mask) { // always restore what was saved if diff
5756 lmc_wodt_mask.u = saved_wodt_mask;
David Hendricks7d48ac52018-03-09 14:30:38 -08005757 ddr_print("WODT_MASK : 0x%016llx\n", lmc_wodt_mask.u);
David Hendricks2004b932018-03-09 13:58:27 -08005758 DRAM_CSR_WRITE(node, BDK_LMCX_WODT_MASK(ddr_interface_num), lmc_wodt_mask.u);
5759 }
5760 }
5761#endif /* WODT_MASK_2R_1S */
5762
5763 } // End HW write-leveling block
5764
5765 // At the end of HW Write Leveling, check on some things...
5766 if (! disable_deskew_training) {
5767
5768 deskew_counts_t dsk_counts;
David Hendricks7d48ac52018-03-09 14:30:38 -08005769 int retry_count = 0;
David Hendricks2004b932018-03-09 13:58:27 -08005770
David Hendricks7d48ac52018-03-09 14:30:38 -08005771 VB_PRT(VBL_FAE, "N%d.LMC%d: Check Deskew Settings before Read-Leveling.\n", node, ddr_interface_num);
David Hendricks2004b932018-03-09 13:58:27 -08005772
David Hendricks7d48ac52018-03-09 14:30:38 -08005773 do {
5774 Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_FAE);
David Hendricks2004b932018-03-09 13:58:27 -08005775
David Hendricks7d48ac52018-03-09 14:30:38 -08005776 // only RAWCARD A or B will not benefit from retraining if there's only saturation
David Hendricks2004b932018-03-09 13:58:27 -08005777 // or any rawcard if there is a nibble error
David Hendricks7d48ac52018-03-09 14:30:38 -08005778 if ((!spd_rawcard_AorB && dsk_counts.saturated > 0) ||
5779 ((dsk_counts.nibrng_errs != 0) || (dsk_counts.nibunl_errs != 0)))
5780 {
5781 retry_count++;
5782 VB_PRT(VBL_FAE, "N%d.LMC%d: Deskew Status indicates saturation or nibble errors - retry %d Training.\n",
5783 node, ddr_interface_num, retry_count);
5784 Perform_Read_Deskew_Training(node, rank_mask, ddr_interface_num,
David Hendricks2004b932018-03-09 13:58:27 -08005785 spd_rawcard_AorB, 0, ddr_interface_64b);
David Hendricks7d48ac52018-03-09 14:30:38 -08005786 } else
5787 break;
5788 } while (retry_count < 5);
David Hendricks2004b932018-03-09 13:58:27 -08005789
5790 // print the last setting only if we had to do retries here
5791 if (retry_count > 0)
5792 Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_NORM);
5793 }
5794
5795 /*
5796 * 6.9.12 LMC Read Leveling
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005797 *
David Hendricks2004b932018-03-09 13:58:27 -08005798 * LMC supports an automatic read-leveling separately per byte-lane using
5799 * the DDR3 multipurpose register predefined pattern for system
5800 * calibration defined in the JEDEC DDR3 specifications.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005801 *
David Hendricks2004b932018-03-09 13:58:27 -08005802 * All of DDR PLL, LMC CK, and LMC DRESET, and early LMC initializations
5803 * must be completed prior to starting this LMC read-leveling sequence.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005804 *
David Hendricks2004b932018-03-09 13:58:27 -08005805 * Software could simply write the desired read-leveling values into
5806 * LMC(0)_RLEVEL_RANK(0..3). This section describes a sequence that uses
5807 * LMC's autoread-leveling capabilities.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005808 *
David Hendricks2004b932018-03-09 13:58:27 -08005809 * When LMC does the read-leveling sequence for a rank, it first enables
5810 * the DDR3 multipurpose register predefined pattern for system
5811 * calibration on the selected DRAM rank via a DDR3 MR3 write, then
5812 * executes 64 RD operations at different internal delay settings, then
5813 * disables the predefined pattern via another DDR3 MR3 write
5814 * operation. LMC determines the pass or fail of each of the 64 settings
5815 * independently for each byte lane, then writes appropriate
5816 * LMC(0)_RLEVEL_RANK(0..3)[BYTE*] values for the rank.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005817 *
David Hendricks2004b932018-03-09 13:58:27 -08005818 * After read-leveling for a rank, software can read the 64 pass/fail
5819 * indications for one byte lane via LMC(0)_RLEVEL_DBG[BITMASK]. Software
5820 * can observe all pass/fail results for all byte lanes in a rank via
5821 * separate read-leveling sequences on the rank with different
5822 * LMC(0)_RLEVEL_CTL[BYTE] values.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005823 *
David Hendricks2004b932018-03-09 13:58:27 -08005824 * The 64 pass/fail results will typically have failures for the low
5825 * delays, followed by a run of some passing settings, followed by more
5826 * failures in the remaining high delays. LMC sets
5827 * LMC(0)_RLEVEL_RANK(0..3)[BYTE*] to one of the passing settings.
5828 * First, LMC selects the longest run of successes in the 64 results. (In
5829 * the unlikely event that there is more than one longest run, LMC
5830 * selects the first one.) Then if LMC(0)_RLEVEL_CTL[OFFSET_EN] = 1 and
5831 * the selected run has more than LMC(0)_RLEVEL_CTL[OFFSET] successes,
5832 * LMC selects the last passing setting in the run minus
5833 * LMC(0)_RLEVEL_CTL[OFFSET]. Otherwise LMC selects the middle setting in
5834 * the run (rounding earlier when necessary). We expect the read-leveling
5835 * sequence to produce good results with the reset values
5836 * LMC(0)_RLEVEL_CTL [OFFSET_EN]=1, LMC(0)_RLEVEL_CTL[OFFSET] = 2.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005837 *
David Hendricks2004b932018-03-09 13:58:27 -08005838 * The read-leveling sequence has the following steps:
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005839 *
David Hendricks2004b932018-03-09 13:58:27 -08005840 * 1. Select desired LMC(0)_RLEVEL_CTL[OFFSET_EN,OFFSET,BYTE] settings.
5841 * Do the remaining substeps 2-4 separately for each rank i with
5842 * attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005843 *
David Hendricks2004b932018-03-09 13:58:27 -08005844 * 2. Without changing any other fields in LMC(0)_CONFIG,
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005845 *
David Hendricks2004b932018-03-09 13:58:27 -08005846 * o write LMC(0)_SEQ_CTL[SEQ_SEL] to select read-leveling
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005847 *
David Hendricks2004b932018-03-09 13:58:27 -08005848 * o write LMC(0)_CONFIG[RANKMASK] = (1 << i)
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005849 *
David Hendricks2004b932018-03-09 13:58:27 -08005850 * o write LMC(0)_SEQ_CTL[INIT_START] = 1
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005851 *
David Hendricks2004b932018-03-09 13:58:27 -08005852 * This initiates the previously-described read-leveling.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005853 *
David Hendricks2004b932018-03-09 13:58:27 -08005854 * 3. Wait until LMC(0)_RLEVEL_RANKi[STATUS] != 2
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005855 *
David Hendricks2004b932018-03-09 13:58:27 -08005856 * LMC will have updated LMC(0)_RLEVEL_RANKi[BYTE*] for all byte lanes
5857 * at this point.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005858 *
David Hendricks2004b932018-03-09 13:58:27 -08005859 * If ECC DRAM is not present (i.e. when DRAM is not attached to the
5860 * DDR_CBS_0_* and DDR_CB<7:0> chip signals, or the DDR_DQS_<4>_* and
5861 * DDR_DQ<35:32> chip signals), write LMC(0)_RLEVEL_RANK*[BYTE8] =
5862 * LMC(0)_RLEVEL_RANK*[BYTE0]. Write LMC(0)_RLEVEL_RANK*[BYTE4] =
5863 * LMC(0)_RLEVEL_RANK*[BYTE0].
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005864 *
David Hendricks2004b932018-03-09 13:58:27 -08005865 * 4. If desired, consult LMC(0)_RLEVEL_DBG[BITMASK] and compare to
5866 * LMC(0)_RLEVEL_RANKi[BYTE*] for the lane selected by
5867 * LMC(0)_RLEVEL_CTL[BYTE]. If desired, modify LMC(0)_RLEVEL_CTL[BYTE]
5868 * to a new value and repeat so that all BITMASKs can be observed.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005869 *
David Hendricks2004b932018-03-09 13:58:27 -08005870 * 5. Initialize LMC(0)_RLEVEL_RANK* values for all unused ranks.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005871 *
David Hendricks2004b932018-03-09 13:58:27 -08005872 * Let rank i be a rank with attached DRAM.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005873 *
David Hendricks2004b932018-03-09 13:58:27 -08005874 * For all ranks j that do not have attached DRAM, set
5875 * LMC(0)_RLEVEL_RANKj = LMC(0)_RLEVEL_RANKi.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01005876 *
David Hendricks2004b932018-03-09 13:58:27 -08005877 * This read-leveling sequence can help select the proper CN70XX ODT
5878 * resistance value (LMC(0)_COMP_CTL2[RODT_CTL]). A hardware-generated
5879 * LMC(0)_RLEVEL_RANKi[BYTEj] value (for a used byte lane j) that is
5880 * drastically different from a neighboring LMC(0)_RLEVEL_RANKi[BYTEk]
5881 * (for a used byte lane k) can indicate that the CN70XX ODT value is
5882 * bad. It is possible to simultaneously optimize both
5883 * LMC(0)_COMP_CTL2[RODT_CTL] and LMC(0)_RLEVEL_RANKn[BYTE*] values by
5884 * performing this read-leveling sequence for several
5885 * LMC(0)_COMP_CTL2[RODT_CTL] values and selecting the one with the best
5886 * LMC(0)_RLEVEL_RANKn[BYTE*] profile for the ranks.
5887 */
5888
5889 {
5890#pragma pack(push,4)
5891 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank;
5892 bdk_lmcx_comp_ctl2_t lmc_comp_ctl2;
5893 bdk_lmcx_rlevel_ctl_t rlevel_ctl;
5894 bdk_lmcx_control_t lmc_control;
5895 bdk_lmcx_modereg_params1_t lmc_modereg_params1;
5896 unsigned char rodt_ctl;
5897 unsigned char rankx = 0;
David Hendricks2004b932018-03-09 13:58:27 -08005898 unsigned char ecc_ena;
5899 unsigned char rtt_nom;
5900 unsigned char rtt_idx;
5901 int min_rtt_nom_idx;
5902 int max_rtt_nom_idx;
5903 int min_rodt_ctl;
5904 int max_rodt_ctl;
5905 int rlevel_debug_loops = 1;
5906 unsigned char save_ddr2t;
5907 int rlevel_avg_loops;
5908 int ddr_rlevel_compute;
5909 int saved_ddr__ptune, saved_ddr__ntune, rlevel_comp_offset;
5910 int saved_int_zqcs_dis = 0;
5911 int disable_sequential_delay_check = 0;
5912 int maximum_adjacent_rlevel_delay_increment = 0;
5913 struct {
5914 uint64_t setting;
5915 int score;
5916 } rlevel_scoreboard[RTT_NOM_OHMS_COUNT][RODT_OHMS_COUNT][4];
5917 int print_nom_ohms;
5918#if PERFECT_BITMASK_COUNTING
5919 typedef struct {
5920 uint8_t count[9][32]; // 8+ECC by 32 values
5921 uint8_t total[9]; // 8+ECC
5922 } rank_perfect_t;
5923 rank_perfect_t rank_perfect_counts[4];
5924#endif
5925
5926#pragma pack(pop)
5927
5928#if PERFECT_BITMASK_COUNTING
5929 memset(rank_perfect_counts, 0, sizeof(rank_perfect_counts));
5930#endif /* PERFECT_BITMASK_COUNTING */
5931
5932 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
5933 save_ddr2t = lmc_control.s.ddr2t;
5934
5935 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5936 ecc_ena = lmc_config.s.ecc_ena;
5937
5938#if 0
5939 {
5940 int save_ref_zqcs_int;
5941 uint64_t temp_delay_usecs;
5942
5943 /* Temporarily select the minimum ZQCS interval and wait
5944 long enough for a few ZQCS calibrations to occur. This
5945 should ensure that the calibration circuitry is
5946 stabilized before read-leveling occurs. */
5947 save_ref_zqcs_int = lmc_config.s.ref_zqcs_int;
5948 lmc_config.s.ref_zqcs_int = 1 | (32<<7); /* set smallest interval */
5949 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
5950 BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5951
5952 /* Compute an appropriate delay based on the current ZQCS
5953 interval. The delay should be long enough for the
5954 current ZQCS delay counter to expire plus ten of the
5955 minimum intarvals to ensure that some calibrations
5956 occur. */
5957 temp_delay_usecs = (((uint64_t)save_ref_zqcs_int >> 7)
5958 * tclk_psecs * 100 * 512 * 128) / (10000*10000)
5959 + 10 * ((uint64_t)32 * tclk_psecs * 100 * 512 * 128) / (10000*10000);
5960
5961 ddr_print ("Waiting %lu usecs for ZQCS calibrations to start\n",
5962 temp_delay_usecs);
5963 bdk_wait_usec(temp_delay_usecs);
5964
5965 lmc_config.s.ref_zqcs_int = save_ref_zqcs_int; /* Restore computed interval */
5966 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
5967 BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
5968 }
5969#endif
5970
5971 if ((s = lookup_env_parameter("ddr_rlevel_2t")) != NULL) {
5972 lmc_control.s.ddr2t = strtoul(s, NULL, 0);
5973 }
5974
5975 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
5976
5977 ddr_print("N%d.LMC%d: Performing Read-Leveling\n", node, ddr_interface_num);
5978
5979 rlevel_ctl.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num));
5980
5981 rlevel_avg_loops = custom_lmc_config->rlevel_average_loops;
5982 if (rlevel_avg_loops == 0) {
5983 rlevel_avg_loops = RLEVEL_AVG_LOOPS_DEFAULT;
5984 if ((dimm_count == 1) || (num_ranks == 1)) // up the samples for these cases
5985 rlevel_avg_loops = rlevel_avg_loops * 2 + 1;
5986 }
5987
5988 ddr_rlevel_compute = custom_lmc_config->rlevel_compute;
5989 rlevel_ctl.s.offset_en = custom_lmc_config->offset_en;
5990 rlevel_ctl.s.offset = spd_rdimm
5991 ? custom_lmc_config->offset_rdimm
5992 : custom_lmc_config->offset_udimm;
5993
5994 rlevel_ctl.s.delay_unload_0 = 1; /* should normally be set */
5995 rlevel_ctl.s.delay_unload_1 = 1; /* should normally be set */
5996 rlevel_ctl.s.delay_unload_2 = 1; /* should normally be set */
5997 rlevel_ctl.s.delay_unload_3 = 1; /* should normally be set */
5998
5999 rlevel_ctl.s.or_dis = 1; // default to get best bitmasks
6000 if ((s = lookup_env_parameter("ddr_rlevel_or_dis")) != NULL) {
6001 rlevel_ctl.s.or_dis = !!strtoul(s, NULL, 0);
6002 }
6003 rlevel_ctl.s.bitmask = 0xff; // should work in 32b mode also
6004 if ((s = lookup_env_parameter("ddr_rlevel_ctl_bitmask")) != NULL) {
6005 rlevel_ctl.s.bitmask = strtoul(s, NULL, 0);
6006 }
6007 debug_print("N%d.LMC%d: RLEVEL_CTL: or_dis=%d, bitmask=0x%02x\n",
6008 node, ddr_interface_num,
6009 rlevel_ctl.s.or_dis, rlevel_ctl.s.bitmask);
6010
6011 rlevel_comp_offset = spd_rdimm
6012 ? custom_lmc_config->rlevel_comp_offset_rdimm
6013 : custom_lmc_config->rlevel_comp_offset_udimm;
6014
6015 if ((s = lookup_env_parameter("ddr_rlevel_offset")) != NULL) {
6016 rlevel_ctl.s.offset = strtoul(s, NULL, 0);
6017 }
6018
6019 if ((s = lookup_env_parameter("ddr_rlevel_offset_en")) != NULL) {
6020 rlevel_ctl.s.offset_en = strtoul(s, NULL, 0);
6021 }
6022 if ((s = lookup_env_parameter("ddr_rlevel_ctl")) != NULL) {
6023 rlevel_ctl.u = strtoul(s, NULL, 0);
6024 }
6025
6026 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_CTL(ddr_interface_num), rlevel_ctl.u);
6027
David Hendricks2004b932018-03-09 13:58:27 -08006028 if ((s = lookup_env_parameter("ddr%d_rlevel_debug_loops", ddr_interface_num)) != NULL) {
6029 rlevel_debug_loops = strtoul(s, NULL, 0);
6030 }
6031
6032 if ((s = lookup_env_parameter("ddr_rtt_nom_auto")) != NULL) {
6033 ddr_rtt_nom_auto = !!strtoul(s, NULL, 0);
6034 }
6035
6036 if ((s = lookup_env_parameter("ddr_rlevel_average")) != NULL) {
6037 rlevel_avg_loops = strtoul(s, NULL, 0);
6038 }
6039
6040 if ((s = lookup_env_parameter("ddr_rlevel_compute")) != NULL) {
6041 ddr_rlevel_compute = strtoul(s, NULL, 0);
6042 }
6043
David Hendricks7d48ac52018-03-09 14:30:38 -08006044 ddr_print("RLEVEL_CTL : 0x%016llx\n", rlevel_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08006045 ddr_print("RLEVEL_OFFSET : %6d\n", rlevel_ctl.s.offset);
6046 ddr_print("RLEVEL_OFFSET_EN : %6d\n", rlevel_ctl.s.offset_en);
6047
6048 /* The purpose for the indexed table is to sort the settings
6049 ** by the ohm value to simplify the testing when incrementing
6050 ** through the settings. (index => ohms) 1=120, 2=60, 3=40,
6051 ** 4=30, 5=20 */
6052 min_rtt_nom_idx = (custom_lmc_config->min_rtt_nom_idx == 0) ? 1 : custom_lmc_config->min_rtt_nom_idx;
6053 max_rtt_nom_idx = (custom_lmc_config->max_rtt_nom_idx == 0) ? 5 : custom_lmc_config->max_rtt_nom_idx;
6054
6055 min_rodt_ctl = (custom_lmc_config->min_rodt_ctl == 0) ? 1 : custom_lmc_config->min_rodt_ctl;
6056 max_rodt_ctl = (custom_lmc_config->max_rodt_ctl == 0) ? 5 : custom_lmc_config->max_rodt_ctl;
6057
6058 if ((s = lookup_env_parameter("ddr_min_rodt_ctl")) != NULL) {
6059 min_rodt_ctl = strtoul(s, NULL, 0);
6060 }
6061 if ((s = lookup_env_parameter("ddr_max_rodt_ctl")) != NULL) {
6062 max_rodt_ctl = strtoul(s, NULL, 0);
6063 }
6064 if ((s = lookup_env_parameter("ddr_min_rtt_nom_idx")) != NULL) {
6065 min_rtt_nom_idx = strtoul(s, NULL, 0);
6066 }
6067 if ((s = lookup_env_parameter("ddr_max_rtt_nom_idx")) != NULL) {
6068 max_rtt_nom_idx = strtoul(s, NULL, 0);
6069 }
6070
6071#ifdef ENABLE_CUSTOM_RLEVEL_TABLE
6072 if (custom_lmc_config->rlevel_table != NULL) {
David Hendricks7d48ac52018-03-09 14:30:38 -08006073 char part_number[21];
David Hendricks2004b932018-03-09 13:58:27 -08006074 /* Check for hard-coded read-leveling settings */
6075 get_dimm_part_number(part_number, node, &dimm_config_table[0], 0, ddr_type);
6076 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
6077 if (!(rank_mask & (1 << rankx)))
6078 continue;
6079
6080 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
6081
6082 i = 0;
6083 while (custom_lmc_config->rlevel_table[i].part != NULL) {
6084 debug_print("DIMM part number:\"%s\", SPD: \"%s\"\n", custom_lmc_config->rlevel_table[i].part, part_number);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01006085 if ((strcmp(part_number, custom_lmc_config->rlevel_table[i].part) == 0)
David Hendricks2004b932018-03-09 13:58:27 -08006086 && (_abs(custom_lmc_config->rlevel_table[i].speed - 2*ddr_hertz/(1000*1000)) < 10 ))
David Hendricks7d48ac52018-03-09 14:30:38 -08006087 {
David Hendricks2004b932018-03-09 13:58:27 -08006088 ddr_print("Using hard-coded read leveling for DIMM part number: \"%s\"\n", part_number);
6089 lmc_rlevel_rank.u = custom_lmc_config->rlevel_table[i].rlevel_rank[ddr_interface_num][rankx];
6090 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
6091 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
6092 display_RL(node, ddr_interface_num, lmc_rlevel_rank, rankx);
6093 rlevel_debug_loops = 0; /* Disable h/w read-leveling */
6094 break;
6095 }
6096 ++i;
6097 }
6098 }
6099 }
6100#endif /* ENABLE_CUSTOM_RLEVEL_TABLE */
6101
6102 while(rlevel_debug_loops--) {
David Hendricks7d48ac52018-03-09 14:30:38 -08006103 /* Initialize the error scoreboard */
6104 memset(rlevel_scoreboard, 0, sizeof(rlevel_scoreboard));
David Hendricks2004b932018-03-09 13:58:27 -08006105
David Hendricks7d48ac52018-03-09 14:30:38 -08006106 if ((s = lookup_env_parameter("ddr_rlevel_comp_offset")) != NULL) {
6107 rlevel_comp_offset = strtoul(s, NULL, 0);
6108 }
David Hendricks2004b932018-03-09 13:58:27 -08006109
David Hendricks7d48ac52018-03-09 14:30:38 -08006110 disable_sequential_delay_check = custom_lmc_config->disable_sequential_delay_check;
David Hendricks2004b932018-03-09 13:58:27 -08006111
David Hendricks7d48ac52018-03-09 14:30:38 -08006112 if ((s = lookup_env_parameter("ddr_disable_sequential_delay_check")) != NULL) {
6113 disable_sequential_delay_check = strtoul(s, NULL, 0);
6114 }
David Hendricks2004b932018-03-09 13:58:27 -08006115
David Hendricks7d48ac52018-03-09 14:30:38 -08006116 maximum_adjacent_rlevel_delay_increment = custom_lmc_config->maximum_adjacent_rlevel_delay_increment;
David Hendricks2004b932018-03-09 13:58:27 -08006117
David Hendricks7d48ac52018-03-09 14:30:38 -08006118 if ((s = lookup_env_parameter("ddr_maximum_adjacent_rlevel_delay_increment")) != NULL) {
6119 maximum_adjacent_rlevel_delay_increment = strtoul(s, NULL, 0);
6120 }
David Hendricks2004b932018-03-09 13:58:27 -08006121
David Hendricks7d48ac52018-03-09 14:30:38 -08006122 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6123 saved_ddr__ptune = lmc_comp_ctl2.s.ddr__ptune;
6124 saved_ddr__ntune = lmc_comp_ctl2.s.ddr__ntune;
David Hendricks2004b932018-03-09 13:58:27 -08006125
David Hendricks7d48ac52018-03-09 14:30:38 -08006126 /* Disable dynamic compensation settings */
6127 if (rlevel_comp_offset != 0) {
6128 lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
6129 lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
David Hendricks2004b932018-03-09 13:58:27 -08006130
David Hendricks7d48ac52018-03-09 14:30:38 -08006131 /* Round up the ptune calculation to bias the odd cases toward ptune */
6132 lmc_comp_ctl2.s.ptune += divide_roundup(rlevel_comp_offset, 2);
6133 lmc_comp_ctl2.s.ntune -= rlevel_comp_offset/2;
David Hendricks2004b932018-03-09 13:58:27 -08006134
David Hendricks7d48ac52018-03-09 14:30:38 -08006135 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
6136 saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
6137 lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
6138 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
David Hendricks2004b932018-03-09 13:58:27 -08006139
David Hendricks7d48ac52018-03-09 14:30:38 -08006140 lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
6141 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
6142 BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6143 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
6144 ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
6145 lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
6146 }
David Hendricks2004b932018-03-09 13:58:27 -08006147
David Hendricks7d48ac52018-03-09 14:30:38 -08006148 lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08006149
David Hendricks7d48ac52018-03-09 14:30:38 -08006150 for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
6151 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
David Hendricks2004b932018-03-09 13:58:27 -08006152
David Hendricks7d48ac52018-03-09 14:30:38 -08006153 /* When the read ODT mask is zero the dyn_rtt_nom_mask is
6154 zero than RTT_NOM will not be changing during
6155 read-leveling. Since the value is fixed we only need
6156 to test it once. */
6157 if (dyn_rtt_nom_mask == 0) {
David Hendricks2004b932018-03-09 13:58:27 -08006158 print_nom_ohms = -1; // flag not to print NOM ohms
6159 if (rtt_idx != min_rtt_nom_idx)
6160 continue;
6161 } else {
6162 if (dyn_rtt_nom_mask & 1) lmc_modereg_params1.s.rtt_nom_00 = rtt_nom;
6163 if (dyn_rtt_nom_mask & 2) lmc_modereg_params1.s.rtt_nom_01 = rtt_nom;
6164 if (dyn_rtt_nom_mask & 4) lmc_modereg_params1.s.rtt_nom_10 = rtt_nom;
6165 if (dyn_rtt_nom_mask & 8) lmc_modereg_params1.s.rtt_nom_11 = rtt_nom;
6166 // FIXME? rank 0 ohms always for the printout?
6167 print_nom_ohms = imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00];
6168 }
6169
David Hendricks7d48ac52018-03-09 14:30:38 -08006170 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
6171 VB_PRT(VBL_TME, "\n");
6172 VB_PRT(VBL_TME, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
6173 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
6174 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
6175 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
6176 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00],
6177 lmc_modereg_params1.s.rtt_nom_11,
6178 lmc_modereg_params1.s.rtt_nom_10,
6179 lmc_modereg_params1.s.rtt_nom_01,
6180 lmc_modereg_params1.s.rtt_nom_00);
David Hendricks2004b932018-03-09 13:58:27 -08006181
David Hendricks7d48ac52018-03-09 14:30:38 -08006182 perform_ddr_init_sequence(node, rank_mask, ddr_interface_num);
David Hendricks2004b932018-03-09 13:58:27 -08006183
6184 // Try RANK outside RODT to rearrange the output...
6185 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
6186 int byte_idx;
6187 rlevel_byte_data_t rlevel_byte[9];
6188 int average_loops;
6189 int rlevel_rank_errors, rlevel_bitmask_errors, rlevel_nonseq_errors;
6190 rlevel_bitmask_t rlevel_bitmask[9];
6191#if PICK_BEST_RANK_SCORE_NOT_AVG
6192 int rlevel_best_rank_score;
6193#endif
6194
6195 if (!(rank_mask & (1 << rankx)))
6196 continue;
6197
6198 for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
6199#if PICK_BEST_RANK_SCORE_NOT_AVG
David Hendricks7d48ac52018-03-09 14:30:38 -08006200 rlevel_best_rank_score = DEFAULT_BEST_RANK_SCORE;
David Hendricks2004b932018-03-09 13:58:27 -08006201#endif
David Hendricks2004b932018-03-09 13:58:27 -08006202 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6203 lmc_comp_ctl2.s.rodt_ctl = rodt_ctl;
6204 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
6205 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6206 bdk_wait_usec(1); /* Give it a little time to take affect */
6207 VB_PRT(VBL_DEV, "Read ODT_CTL : 0x%x (%d ohms)\n",
6208 lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
6209
David Hendricks7d48ac52018-03-09 14:30:38 -08006210 memset(rlevel_byte, 0, sizeof(rlevel_byte));
David Hendricks2004b932018-03-09 13:58:27 -08006211
David Hendricks7d48ac52018-03-09 14:30:38 -08006212 for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) {
6213 rlevel_bitmask_errors = 0;
David Hendricks2004b932018-03-09 13:58:27 -08006214
David Hendricks7d48ac52018-03-09 14:30:38 -08006215 if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
6216 /* Clear read-level delays */
6217 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
David Hendricks2004b932018-03-09 13:58:27 -08006218
6219 /* read-leveling */
David Hendricks7d48ac52018-03-09 14:30:38 -08006220 perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1);
David Hendricks2004b932018-03-09 13:58:27 -08006221
David Hendricks7d48ac52018-03-09 14:30:38 -08006222 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
6223 status, ==, 3, 1000000))
6224 {
David Hendricks2004b932018-03-09 13:58:27 -08006225 error_print("ERROR: Timeout waiting for RLEVEL\n");
6226 }
David Hendricks7d48ac52018-03-09 14:30:38 -08006227 }
David Hendricks2004b932018-03-09 13:58:27 -08006228
David Hendricks7d48ac52018-03-09 14:30:38 -08006229 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08006230
David Hendricks7d48ac52018-03-09 14:30:38 -08006231 { // start bitmask interpretation block
David Hendricks2004b932018-03-09 13:58:27 -08006232 int redoing_nonseq_errs = 0;
6233
6234 memset(rlevel_bitmask, 0, sizeof(rlevel_bitmask));
6235
David Hendricks7d48ac52018-03-09 14:30:38 -08006236 if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) {
6237 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank_aside;
6238 bdk_lmcx_modereg_params0_t lmc_modereg_params0;
David Hendricks2004b932018-03-09 13:58:27 -08006239
David Hendricks7d48ac52018-03-09 14:30:38 -08006240 /* A-side */
6241 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
6242 lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
6243 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08006244
David Hendricks7d48ac52018-03-09 14:30:38 -08006245 /* Clear read-level delays */
6246 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
David Hendricks2004b932018-03-09 13:58:27 -08006247
David Hendricks7d48ac52018-03-09 14:30:38 -08006248 perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
David Hendricks2004b932018-03-09 13:58:27 -08006249
David Hendricks7d48ac52018-03-09 14:30:38 -08006250 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
6251 status, ==, 3, 1000000))
6252 {
6253 error_print("ERROR: Timeout waiting for RLEVEL\n");
David Hendricks2004b932018-03-09 13:58:27 -08006254
David Hendricks7d48ac52018-03-09 14:30:38 -08006255 }
6256 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08006257
David Hendricks7d48ac52018-03-09 14:30:38 -08006258 lmc_rlevel_rank_aside.u = lmc_rlevel_rank.u;
David Hendricks2004b932018-03-09 13:58:27 -08006259
David Hendricks7d48ac52018-03-09 14:30:38 -08006260 rlevel_bitmask[0].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 0);
6261 rlevel_bitmask[1].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 1);
6262 rlevel_bitmask[2].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 2);
6263 rlevel_bitmask[3].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 3);
6264 rlevel_bitmask[8].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 8);
6265 /* A-side complete */
David Hendricks2004b932018-03-09 13:58:27 -08006266
6267
David Hendricks7d48ac52018-03-09 14:30:38 -08006268 /* B-side */
6269 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
6270 lmc_modereg_params0.s.mprloc = 3; /* MPR Page 0 Location 3 */
6271 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08006272
David Hendricks7d48ac52018-03-09 14:30:38 -08006273 /* Clear read-level delays */
6274 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), 0);
David Hendricks2004b932018-03-09 13:58:27 -08006275
David Hendricks7d48ac52018-03-09 14:30:38 -08006276 perform_octeon3_ddr3_sequence(node, 1 << rankx, ddr_interface_num, 1); /* read-leveling */
David Hendricks2004b932018-03-09 13:58:27 -08006277
David Hendricks7d48ac52018-03-09 14:30:38 -08006278 if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx),
6279 status, ==, 3, 1000000))
6280 {
6281 error_print("ERROR: Timeout waiting for RLEVEL\n");
6282 }
6283 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08006284
David Hendricks7d48ac52018-03-09 14:30:38 -08006285 rlevel_bitmask[4].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 4);
6286 rlevel_bitmask[5].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 5);
6287 rlevel_bitmask[6].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 6);
6288 rlevel_bitmask[7].bm = octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, 7);
6289 /* B-side complete */
David Hendricks2004b932018-03-09 13:58:27 -08006290
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01006291
David Hendricks7d48ac52018-03-09 14:30:38 -08006292 update_rlevel_rank_struct(&lmc_rlevel_rank, 0, lmc_rlevel_rank_aside.cn83xx.byte0);
6293 update_rlevel_rank_struct(&lmc_rlevel_rank, 1, lmc_rlevel_rank_aside.cn83xx.byte1);
6294 update_rlevel_rank_struct(&lmc_rlevel_rank, 2, lmc_rlevel_rank_aside.cn83xx.byte2);
6295 update_rlevel_rank_struct(&lmc_rlevel_rank, 3, lmc_rlevel_rank_aside.cn83xx.byte3);
6296 update_rlevel_rank_struct(&lmc_rlevel_rank, 8, lmc_rlevel_rank_aside.cn83xx.byte8); /* ECC A-side */
David Hendricks2004b932018-03-09 13:58:27 -08006297
David Hendricks7d48ac52018-03-09 14:30:38 -08006298 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
6299 lmc_modereg_params0.s.mprloc = 0; /* MPR Page 0 Location 0 */
6300 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08006301
David Hendricks7d48ac52018-03-09 14:30:38 -08006302 } /* if (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM)) */
David Hendricks2004b932018-03-09 13:58:27 -08006303
David Hendricks7d48ac52018-03-09 14:30:38 -08006304 /*
David Hendricks2004b932018-03-09 13:58:27 -08006305 * Evaluate the quality of the read-leveling delays from the bitmasks.
6306 * Also save off a software computed read-leveling mask that may be
6307 * used later to qualify the delay results from Octeon.
6308 */
David Hendricks7d48ac52018-03-09 14:30:38 -08006309 for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
David Hendricks2004b932018-03-09 13:58:27 -08006310 int bmerr;
David Hendricks7d48ac52018-03-09 14:30:38 -08006311 if (!(ddr_interface_bytemask&(1<<byte_idx)))
6312 continue;
6313 if (! (rlevel_separate_ab && spd_rdimm && (ddr_type == DDR4_DRAM))) {
6314 rlevel_bitmask[byte_idx].bm =
6315 octeon_read_lmcx_ddr3_rlevel_dbg(node, ddr_interface_num, byte_idx);
6316 }
David Hendricks2004b932018-03-09 13:58:27 -08006317 bmerr = validate_ddr3_rlevel_bitmask(&rlevel_bitmask[byte_idx], ddr_type);
David Hendricks7d48ac52018-03-09 14:30:38 -08006318 rlevel_bitmask[byte_idx].errs = bmerr;
6319 rlevel_bitmask_errors += bmerr;
David Hendricks2004b932018-03-09 13:58:27 -08006320#if PERFECT_BITMASK_COUNTING
6321 if ((ddr_type == DDR4_DRAM) && !bmerr) { // count only the "perfect" bitmasks
6322 // FIXME: could optimize this a bit?
6323 int delay = get_rlevel_rank_struct(&lmc_rlevel_rank, byte_idx);
6324 rank_perfect_counts[rankx].count[byte_idx][delay] += 1;
6325 rank_perfect_counts[rankx].total[byte_idx] += 1;
6326 }
6327#endif /* PERFECT_BITMASK_COUNTING */
David Hendricks7d48ac52018-03-09 14:30:38 -08006328 }
David Hendricks2004b932018-03-09 13:58:27 -08006329
David Hendricks7d48ac52018-03-09 14:30:38 -08006330 /* Set delays for unused bytes to match byte 0. */
6331 for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
6332 if (ddr_interface_bytemask & (1 << byte_idx))
6333 continue;
6334 update_rlevel_rank_struct(&lmc_rlevel_rank, byte_idx, lmc_rlevel_rank.cn83xx.byte0);
6335 }
David Hendricks2004b932018-03-09 13:58:27 -08006336
David Hendricks7d48ac52018-03-09 14:30:38 -08006337 /* Save a copy of the byte delays in physical
6338 order for sequential evaluation. */
6339 unpack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, lmc_rlevel_rank);
David Hendricks2004b932018-03-09 13:58:27 -08006340 redo_nonseq_errs:
6341
6342 rlevel_nonseq_errors = 0;
6343
David Hendricks7d48ac52018-03-09 14:30:38 -08006344 if (! disable_sequential_delay_check) {
6345 if ((ddr_interface_bytemask & 0xff) == 0xff) {
6346 /* Evaluate delay sequence across the whole range of bytes for standard dimms. */
6347 if ((spd_dimm_type == 1) || (spd_dimm_type == 5)) { /* 1=RDIMM, 5=Mini-RDIMM */
6348 int register_adjacent_delay = _abs(rlevel_byte[4].delay - rlevel_byte[5].delay);
6349 /* Registered dimm topology routes from the center. */
6350 rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
6351 maximum_adjacent_rlevel_delay_increment);
6352 rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 5, 7+ecc_ena,
6353 maximum_adjacent_rlevel_delay_increment);
David Hendricks2004b932018-03-09 13:58:27 -08006354 // byte 5 sqerrs never gets cleared for RDIMMs
6355 rlevel_byte[5].sqerrs = 0;
David Hendricks7d48ac52018-03-09 14:30:38 -08006356 if (register_adjacent_delay > 1) {
6357 /* Assess proximity of bytes on opposite sides of register */
6358 rlevel_nonseq_errors += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08006359 // update byte 5 error
David Hendricks7d48ac52018-03-09 14:30:38 -08006360 rlevel_byte[5].sqerrs += (register_adjacent_delay-1) * RLEVEL_ADJACENT_DELAY_ERROR;
David Hendricks2004b932018-03-09 13:58:27 -08006361 }
David Hendricks7d48ac52018-03-09 14:30:38 -08006362 }
6363 if ((spd_dimm_type == 2) || (spd_dimm_type == 6)) { /* 2=UDIMM, 6=Mini-UDIMM */
6364 /* Unbuffered dimm topology routes from end to end. */
6365 rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 7+ecc_ena,
6366 maximum_adjacent_rlevel_delay_increment);
6367 }
6368 } else {
6369 rlevel_nonseq_errors += nonsequential_delays(rlevel_byte, 0, 3+ecc_ena,
6370 maximum_adjacent_rlevel_delay_increment);
6371 }
6372 } /* if (! disable_sequential_delay_check) */
David Hendricks2004b932018-03-09 13:58:27 -08006373
6374#if 0
6375 // FIXME FIXME: disabled for now, it was too much...
6376
6377 // Calculate total errors for the rank:
6378 // we do NOT add nonsequential errors if mini-[RU]DIMM or x16;
6379 // mini-DIMMs and x16 devices have unusual sequence geometries.
6380 // Make the final scores for them depend only on the bitmasks...
6381 rlevel_rank_errors = rlevel_bitmask_errors;
6382 if ((spd_dimm_type != 5) &&
6383 (spd_dimm_type != 6) &&
6384 (dram_width != 16))
6385 {
6386 rlevel_rank_errors += rlevel_nonseq_errors;
6387 }
6388#else
6389 rlevel_rank_errors = rlevel_bitmask_errors + rlevel_nonseq_errors;
6390#endif
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01006391
David Hendricks7d48ac52018-03-09 14:30:38 -08006392 // print original sample here only if we are not really averaging or picking best
David Hendricks2004b932018-03-09 13:58:27 -08006393 // also do not print if we were redoing the NONSEQ score for using COMPUTED
David Hendricks7d48ac52018-03-09 14:30:38 -08006394 if (!redoing_nonseq_errs && ((rlevel_avg_loops < 2) || dram_is_verbose(VBL_DEV2))) {
David Hendricks2004b932018-03-09 13:58:27 -08006395 display_RL_BM(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
6396 display_RL_BM_scores(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
6397 display_RL_SEQ_scores(node, ddr_interface_num, rankx, rlevel_byte, ecc_ena);
David Hendricks7d48ac52018-03-09 14:30:38 -08006398 display_RL_with_score(node, ddr_interface_num, lmc_rlevel_rank, rankx, rlevel_rank_errors);
6399 }
David Hendricks2004b932018-03-09 13:58:27 -08006400
David Hendricks7d48ac52018-03-09 14:30:38 -08006401 if (ddr_rlevel_compute) {
David Hendricks2004b932018-03-09 13:58:27 -08006402 if (!redoing_nonseq_errs) {
6403 /* Recompute the delays based on the bitmask */
6404 for (byte_idx = 0; byte_idx < (8+ecc_ena); ++byte_idx) {
6405 if (!(ddr_interface_bytemask & (1 << byte_idx)))
6406 continue;
6407 update_rlevel_rank_struct(&lmc_rlevel_rank, byte_idx,
6408 compute_ddr3_rlevel_delay(rlevel_bitmask[byte_idx].mstart,
6409 rlevel_bitmask[byte_idx].width,
6410 rlevel_ctl));
6411 }
6412
6413 /* Override the copy of byte delays with the computed results. */
6414 unpack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, lmc_rlevel_rank);
6415
6416 redoing_nonseq_errs = 1;
6417 goto redo_nonseq_errs;
6418
6419 } else {
6420 /* now print this if already printed the original sample */
6421 if ((rlevel_avg_loops < 2) || dram_is_verbose(VBL_DEV2)) {
6422 display_RL_with_computed(node, ddr_interface_num,
6423 lmc_rlevel_rank, rankx,
6424 rlevel_rank_errors);
6425 }
6426 }
David Hendricks7d48ac52018-03-09 14:30:38 -08006427 } /* if (ddr_rlevel_compute) */
David Hendricks2004b932018-03-09 13:58:27 -08006428
David Hendricks7d48ac52018-03-09 14:30:38 -08006429 } // end bitmask interpretation block
David Hendricks2004b932018-03-09 13:58:27 -08006430
6431#if PICK_BEST_RANK_SCORE_NOT_AVG
6432
David Hendricks7d48ac52018-03-09 14:30:38 -08006433 // if it is a better (lower) score, then keep it
6434 if (rlevel_rank_errors < rlevel_best_rank_score) {
6435 rlevel_best_rank_score = rlevel_rank_errors;
David Hendricks2004b932018-03-09 13:58:27 -08006436
David Hendricks7d48ac52018-03-09 14:30:38 -08006437 // save the new best delays and best errors
6438 for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
6439 rlevel_byte[byte_idx].best = rlevel_byte[byte_idx].delay;
6440 rlevel_byte[byte_idx].bestsq = rlevel_byte[byte_idx].sqerrs;
David Hendricks2004b932018-03-09 13:58:27 -08006441 // save bitmasks and their scores as well
6442 // xlate UNPACKED index to PACKED index to get from rlevel_bitmask
David Hendricks7d48ac52018-03-09 14:30:38 -08006443 rlevel_byte[byte_idx].bm = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].bm;
6444 rlevel_byte[byte_idx].bmerrs = rlevel_bitmask[XUP(byte_idx, !!ecc_ena)].errs;
6445 }
6446 }
David Hendricks2004b932018-03-09 13:58:27 -08006447#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
6448
David Hendricks7d48ac52018-03-09 14:30:38 -08006449 /* Accumulate the total score across averaging loops for this setting */
6450 debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score: %d [%d]\n",
6451 rtt_nom, rodt_ctl, rankx, rlevel_rank_errors, average_loops);
6452 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score += rlevel_rank_errors;
David Hendricks2004b932018-03-09 13:58:27 -08006453
David Hendricks7d48ac52018-03-09 14:30:38 -08006454 /* Accumulate the delay totals and loop counts
6455 necessary to compute average delay results */
6456 for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
6457 if (rlevel_byte[byte_idx].delay != 0) { /* Don't include delay=0 in the average */
6458 ++rlevel_byte[byte_idx].loop_count;
6459 rlevel_byte[byte_idx].loop_total += rlevel_byte[byte_idx].delay;
6460 }
6461 } /* for (byte_idx = 0; byte_idx < 9; ++byte_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08006462#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
6463
David Hendricks7d48ac52018-03-09 14:30:38 -08006464 } /* for (average_loops = 0; average_loops < rlevel_avg_loops; average_loops++) */
David Hendricks2004b932018-03-09 13:58:27 -08006465
6466#if PICK_BEST_RANK_SCORE_NOT_AVG
6467
David Hendricks7d48ac52018-03-09 14:30:38 -08006468 /* We recorded the best score across the averaging loops */
6469 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score = rlevel_best_rank_score;
David Hendricks2004b932018-03-09 13:58:27 -08006470
David Hendricks7d48ac52018-03-09 14:30:38 -08006471 /* Restore the delays from the best fields that go with the best score */
6472 for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
6473 rlevel_byte[byte_idx].delay = rlevel_byte[byte_idx].best;
6474 rlevel_byte[byte_idx].sqerrs = rlevel_byte[byte_idx].bestsq;
6475 }
David Hendricks2004b932018-03-09 13:58:27 -08006476#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
6477
David Hendricks7d48ac52018-03-09 14:30:38 -08006478 /* Compute the average score across averaging loops */
6479 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score =
6480 divide_nint(rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score, rlevel_avg_loops);
David Hendricks2004b932018-03-09 13:58:27 -08006481
David Hendricks7d48ac52018-03-09 14:30:38 -08006482 /* Compute the average delay results */
6483 for (byte_idx=0; byte_idx < 9; ++byte_idx) {
6484 if (rlevel_byte[byte_idx].loop_count == 0)
6485 rlevel_byte[byte_idx].loop_count = 1;
6486 rlevel_byte[byte_idx].delay = divide_nint(rlevel_byte[byte_idx].loop_total,
6487 rlevel_byte[byte_idx].loop_count);
6488 }
David Hendricks2004b932018-03-09 13:58:27 -08006489#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
6490
David Hendricks7d48ac52018-03-09 14:30:38 -08006491 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08006492
David Hendricks7d48ac52018-03-09 14:30:38 -08006493 pack_rlevel_settings(ddr_interface_bytemask, ecc_ena, rlevel_byte, &lmc_rlevel_rank);
David Hendricks2004b932018-03-09 13:58:27 -08006494
David Hendricks7d48ac52018-03-09 14:30:38 -08006495 if (rlevel_avg_loops > 1) {
David Hendricks2004b932018-03-09 13:58:27 -08006496#if PICK_BEST_RANK_SCORE_NOT_AVG
6497 // restore the "best" bitmasks and their scores for printing
6498 for (byte_idx = 0; byte_idx < 9; ++byte_idx) {
6499 if ((ddr_interface_bytemask & (1 << byte_idx)) == 0)
6500 continue;
6501 // xlate PACKED index to UNPACKED index to get from rlevel_byte
6502 rlevel_bitmask[byte_idx].bm = rlevel_byte[XPU(byte_idx, !!ecc_ena)].bm;
6503 rlevel_bitmask[byte_idx].errs = rlevel_byte[XPU(byte_idx, !!ecc_ena)].bmerrs;
6504 }
6505 // print bitmasks/scores here only for DEV // FIXME? lower VBL?
6506 if (dram_is_verbose(VBL_DEV)) {
6507 display_RL_BM(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
6508 display_RL_BM_scores(node, ddr_interface_num, rankx, rlevel_bitmask, ecc_ena);
6509 display_RL_SEQ_scores(node, ddr_interface_num, rankx, rlevel_byte, ecc_ena);
6510 }
6511
6512 display_RL_with_RODT(node, ddr_interface_num, lmc_rlevel_rank, rankx,
6513 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score,
6514 print_nom_ohms, imp_values->rodt_ohms[rodt_ctl],
6515 WITH_RODT_BESTSCORE);
6516
6517#else /* PICK_BEST_RANK_SCORE_NOT_AVG */
David Hendricks7d48ac52018-03-09 14:30:38 -08006518 display_RL_with_average(node, ddr_interface_num, lmc_rlevel_rank, rankx,
6519 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
David Hendricks2004b932018-03-09 13:58:27 -08006520#endif /* PICK_BEST_RANK_SCORE_NOT_AVG */
6521
David Hendricks7d48ac52018-03-09 14:30:38 -08006522 } /* if (rlevel_avg_loops > 1) */
David Hendricks2004b932018-03-09 13:58:27 -08006523
David Hendricks7d48ac52018-03-09 14:30:38 -08006524 rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].setting = lmc_rlevel_rank.u;
David Hendricks2004b932018-03-09 13:58:27 -08006525
6526 } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
6527 } /* for (rankx = 0; rankx < dimm_count*4; rankx++) */
David Hendricks7d48ac52018-03-09 14:30:38 -08006528 } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<max_rtt_nom_idx; ++rtt_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08006529
6530
David Hendricks7d48ac52018-03-09 14:30:38 -08006531 /* Re-enable dynamic compensation settings. */
6532 if (rlevel_comp_offset != 0) {
6533 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08006534
David Hendricks7d48ac52018-03-09 14:30:38 -08006535 lmc_comp_ctl2.s.ptune = 0;
6536 lmc_comp_ctl2.s.ntune = 0;
6537 lmc_comp_ctl2.s.byp = 0; /* Disable bypass mode */
6538 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
6539 BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read once */
David Hendricks2004b932018-03-09 13:58:27 -08006540
David Hendricks7d48ac52018-03-09 14:30:38 -08006541 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
6542 ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
6543 lmc_comp_ctl2.s.ddr__ptune, lmc_comp_ctl2.s.ddr__ntune);
David Hendricks2004b932018-03-09 13:58:27 -08006544
David Hendricks7d48ac52018-03-09 14:30:38 -08006545 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
6546 lmc_control.s.int_zqcs_dis = saved_int_zqcs_dis; /* Restore original setting */
6547 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
David Hendricks2004b932018-03-09 13:58:27 -08006548
David Hendricks7d48ac52018-03-09 14:30:38 -08006549 }
David Hendricks2004b932018-03-09 13:58:27 -08006550
6551
David Hendricks7d48ac52018-03-09 14:30:38 -08006552 {
6553 int override_compensation = 0;
6554 if ((s = lookup_env_parameter("ddr__ptune")) != NULL) {
6555 saved_ddr__ptune = strtoul(s, NULL, 0);
6556 override_compensation = 1;
6557 }
6558 if ((s = lookup_env_parameter("ddr__ntune")) != NULL) {
6559 saved_ddr__ntune = strtoul(s, NULL, 0);
6560 override_compensation = 1;
6561 }
6562 if (override_compensation) {
6563 lmc_comp_ctl2.s.ptune = saved_ddr__ptune;
6564 lmc_comp_ctl2.s.ntune = saved_ddr__ntune;
David Hendricks2004b932018-03-09 13:58:27 -08006565
David Hendricks7d48ac52018-03-09 14:30:38 -08006566 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
6567 saved_int_zqcs_dis = lmc_control.s.int_zqcs_dis;
6568 lmc_control.s.int_zqcs_dis = 1; /* Disable ZQCS while in bypass. */
6569 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
David Hendricks2004b932018-03-09 13:58:27 -08006570
David Hendricks7d48ac52018-03-09 14:30:38 -08006571 lmc_comp_ctl2.s.byp = 1; /* Enable bypass mode */
6572 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
6573 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num)); /* Read again */
David Hendricks2004b932018-03-09 13:58:27 -08006574
David Hendricks7d48ac52018-03-09 14:30:38 -08006575 ddr_print("DDR__PTUNE/DDR__NTUNE : %d/%d\n",
6576 lmc_comp_ctl2.s.ptune, lmc_comp_ctl2.s.ntune);
6577 }
6578 }
6579 { /* Evaluation block */
6580 int best_rodt_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
6581 int auto_rodt_ctl = 0;
6582 int auto_rtt_nom = 0;
6583 int rodt_score;
6584 int rodt_row_skip_mask = 0;
David Hendricks2004b932018-03-09 13:58:27 -08006585
David Hendricks7d48ac52018-03-09 14:30:38 -08006586 // just add specific RODT rows to the skip mask for DDR4 at this time...
6587 if (ddr_type == DDR4_DRAM) {
6588 rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_34_ohm); // skip RODT row 34 ohms for all DDR4 types
6589 rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_40_ohm); // skip RODT row 40 ohms for all DDR4 types
David Hendricks2004b932018-03-09 13:58:27 -08006590#if ADD_48_OHM_SKIP
David Hendricks7d48ac52018-03-09 14:30:38 -08006591 rodt_row_skip_mask |= (1 << ddr4_rodt_ctl_48_ohm); // skip RODT row 48 ohms for all DDR4 types
David Hendricks2004b932018-03-09 13:58:27 -08006592#endif /* ADD_48OHM_SKIP */
6593#if NOSKIP_40_48_OHM
David Hendricks7d48ac52018-03-09 14:30:38 -08006594 // For now, do not skip RODT row 40 or 48 ohm when ddr_hertz is above 1075 MHz
6595 if (ddr_hertz > 1075000000) {
6596 rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_40_ohm); // noskip RODT row 40 ohms
6597 rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
6598 }
David Hendricks2004b932018-03-09 13:58:27 -08006599#endif /* NOSKIP_40_48_OHM */
6600#if NOSKIP_48_STACKED
David Hendricks7d48ac52018-03-09 14:30:38 -08006601 // For now, do not skip RODT row 48 ohm for 2Rx4 stacked die DIMMs
6602 if ((is_stacked_die) && (num_ranks == 2) && (dram_width == 4)) {
6603 rodt_row_skip_mask &= ~(1 << ddr4_rodt_ctl_48_ohm); // noskip RODT row 48 ohms
6604 }
David Hendricks2004b932018-03-09 13:58:27 -08006605#endif /* NOSKIP_48_STACKED */
6606#if NOSKIP_FOR_MINI
6607 // for now, leave all rows eligible when we have mini-DIMMs...
6608 if ((spd_dimm_type == 5) || (spd_dimm_type == 6)) {
6609 rodt_row_skip_mask = 0;
6610 }
6611#endif /* NOSKIP_FOR_MINI */
6612#if NOSKIP_FOR_2S_1R
6613 // for now, leave all rows eligible when we have a 2-slot 1-rank config
6614 if ((dimm_count == 2) && (num_ranks == 1)) {
6615 rodt_row_skip_mask = 0;
6616 }
6617#endif /* NOSKIP_FOR_2S_1R */
David Hendricks7d48ac52018-03-09 14:30:38 -08006618 }
David Hendricks2004b932018-03-09 13:58:27 -08006619
David Hendricks7d48ac52018-03-09 14:30:38 -08006620 VB_PRT(VBL_DEV, "Evaluating Read-Leveling Scoreboard for AUTO settings.\n");
6621 for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) {
6622 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
David Hendricks2004b932018-03-09 13:58:27 -08006623
David Hendricks7d48ac52018-03-09 14:30:38 -08006624 /* When the read ODT mask is zero the dyn_rtt_nom_mask is
6625 zero than RTT_NOM will not be changing during
6626 read-leveling. Since the value is fixed we only need
6627 to test it once. */
6628 if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
6629 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006630
David Hendricks7d48ac52018-03-09 14:30:38 -08006631 for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) {
6632 rodt_score = 0;
6633 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
6634 if (!(rank_mask & (1 << rankx)))
6635 continue;
6636 debug_print("rlevel_scoreboard[rtt_nom=%d][rodt_ctl=%d][rankx=%d].score:%d\n",
6637 rtt_nom, rodt_ctl, rankx, rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score);
6638 rodt_score += rlevel_scoreboard[rtt_nom][rodt_ctl][rankx].score;
6639 }
6640 // FIXME: do we need to skip RODT rows here, like we do below in the by-RANK settings?
David Hendricks2004b932018-03-09 13:58:27 -08006641
David Hendricks7d48ac52018-03-09 14:30:38 -08006642 /* When using automatic ODT settings use the ODT
6643 settings associated with the best score for
6644 all of the tested ODT combinations. */
David Hendricks2004b932018-03-09 13:58:27 -08006645
David Hendricks7d48ac52018-03-09 14:30:38 -08006646 if ((rodt_score < best_rodt_score) || // always take lower score, OR
6647 ((rodt_score == best_rodt_score) && // take same score if RODT ohms are higher
6648 (imp_values->rodt_ohms[rodt_ctl] > imp_values->rodt_ohms[auto_rodt_ctl])))
6649 {
6650 debug_print("AUTO: new best score for rodt:%d (%3d), new score:%d, previous score:%d\n",
6651 rodt_ctl, imp_values->rodt_ohms[rodt_ctl], rodt_score, best_rodt_score);
6652 best_rodt_score = rodt_score;
6653 auto_rodt_ctl = rodt_ctl;
6654 auto_rtt_nom = rtt_nom;
6655 }
6656 } /* for (rodt_ctl=max_rodt_ctl; rodt_ctl>=min_rodt_ctl; --rodt_ctl) */
6657 } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08006658
David Hendricks7d48ac52018-03-09 14:30:38 -08006659 lmc_modereg_params1.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08006660
David Hendricks7d48ac52018-03-09 14:30:38 -08006661 if (ddr_rtt_nom_auto) {
6662 /* Store the automatically set RTT_NOM value */
6663 if (dyn_rtt_nom_mask & 1) lmc_modereg_params1.s.rtt_nom_00 = auto_rtt_nom;
6664 if (dyn_rtt_nom_mask & 2) lmc_modereg_params1.s.rtt_nom_01 = auto_rtt_nom;
6665 if (dyn_rtt_nom_mask & 4) lmc_modereg_params1.s.rtt_nom_10 = auto_rtt_nom;
6666 if (dyn_rtt_nom_mask & 8) lmc_modereg_params1.s.rtt_nom_11 = auto_rtt_nom;
6667 } else {
6668 /* restore the manual settings to the register */
6669 lmc_modereg_params1.s.rtt_nom_00 = default_rtt_nom[0];
6670 lmc_modereg_params1.s.rtt_nom_01 = default_rtt_nom[1];
6671 lmc_modereg_params1.s.rtt_nom_10 = default_rtt_nom[2];
6672 lmc_modereg_params1.s.rtt_nom_11 = default_rtt_nom[3];
6673 }
David Hendricks2004b932018-03-09 13:58:27 -08006674
David Hendricks7d48ac52018-03-09 14:30:38 -08006675 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS1(ddr_interface_num), lmc_modereg_params1.u);
6676 VB_PRT(VBL_DEV, "RTT_NOM %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
David Hendricks2004b932018-03-09 13:58:27 -08006677 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_11],
6678 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_10],
6679 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_01],
6680 imp_values->rtt_nom_ohms[lmc_modereg_params1.s.rtt_nom_00],
6681 lmc_modereg_params1.s.rtt_nom_11,
6682 lmc_modereg_params1.s.rtt_nom_10,
6683 lmc_modereg_params1.s.rtt_nom_01,
6684 lmc_modereg_params1.s.rtt_nom_00);
6685
David Hendricks7d48ac52018-03-09 14:30:38 -08006686 VB_PRT(VBL_DEV, "RTT_WR %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
David Hendricks2004b932018-03-09 13:58:27 -08006687 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 3)],
6688 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 2)],
6689 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 1)],
6690 imp_values->rtt_wr_ohms[EXTR_WR(lmc_modereg_params1.u, 0)],
6691 EXTR_WR(lmc_modereg_params1.u, 3),
6692 EXTR_WR(lmc_modereg_params1.u, 2),
6693 EXTR_WR(lmc_modereg_params1.u, 1),
6694 EXTR_WR(lmc_modereg_params1.u, 0));
6695
David Hendricks7d48ac52018-03-09 14:30:38 -08006696 VB_PRT(VBL_DEV, "DIC %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
David Hendricks2004b932018-03-09 13:58:27 -08006697 imp_values->dic_ohms[lmc_modereg_params1.s.dic_11],
6698 imp_values->dic_ohms[lmc_modereg_params1.s.dic_10],
6699 imp_values->dic_ohms[lmc_modereg_params1.s.dic_01],
6700 imp_values->dic_ohms[lmc_modereg_params1.s.dic_00],
6701 lmc_modereg_params1.s.dic_11,
6702 lmc_modereg_params1.s.dic_10,
6703 lmc_modereg_params1.s.dic_01,
6704 lmc_modereg_params1.s.dic_00);
6705
David Hendricks7d48ac52018-03-09 14:30:38 -08006706 if (ddr_type == DDR4_DRAM) {
6707 bdk_lmcx_modereg_params2_t lmc_modereg_params2;
6708 /*
6709 * We must read the CSR, and not depend on odt_config[odt_idx].odt_mask2,
6710 * since we could have overridden values with envvars.
6711 * NOTE: this corrects the printout, since the CSR is not written with the old values...
6712 */
6713 lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08006714
David Hendricks7d48ac52018-03-09 14:30:38 -08006715 VB_PRT(VBL_DEV, "RTT_PARK %3d, %3d, %3d, %3d ohms : %x,%x,%x,%x\n",
6716 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_11],
6717 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_10],
6718 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_01],
6719 imp_values->rtt_nom_ohms[lmc_modereg_params2.s.rtt_park_00],
6720 lmc_modereg_params2.s.rtt_park_11,
6721 lmc_modereg_params2.s.rtt_park_10,
6722 lmc_modereg_params2.s.rtt_park_01,
6723 lmc_modereg_params2.s.rtt_park_00);
David Hendricks2004b932018-03-09 13:58:27 -08006724
David Hendricks7d48ac52018-03-09 14:30:38 -08006725 VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_RANGE",
6726 lmc_modereg_params2.s.vref_range_11,
6727 lmc_modereg_params2.s.vref_range_10,
6728 lmc_modereg_params2.s.vref_range_01,
6729 lmc_modereg_params2.s.vref_range_00);
David Hendricks2004b932018-03-09 13:58:27 -08006730
David Hendricks7d48ac52018-03-09 14:30:38 -08006731 VB_PRT(VBL_DEV, "%-45s : 0x%x,0x%x,0x%x,0x%x\n", "VREF_VALUE",
6732 lmc_modereg_params2.s.vref_value_11,
6733 lmc_modereg_params2.s.vref_value_10,
6734 lmc_modereg_params2.s.vref_value_01,
6735 lmc_modereg_params2.s.vref_value_00);
6736 }
David Hendricks2004b932018-03-09 13:58:27 -08006737
David Hendricks7d48ac52018-03-09 14:30:38 -08006738 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6739 if (ddr_rodt_ctl_auto)
6740 lmc_comp_ctl2.s.rodt_ctl = auto_rodt_ctl;
6741 else
6742 lmc_comp_ctl2.s.rodt_ctl = default_rodt_ctl; // back to the original setting
6743 DRAM_CSR_WRITE(node, BDK_LMCX_COMP_CTL2(ddr_interface_num), lmc_comp_ctl2.u);
6744 lmc_comp_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_COMP_CTL2(ddr_interface_num));
6745 VB_PRT(VBL_DEV, "Read ODT_CTL : 0x%x (%d ohms)\n",
6746 lmc_comp_ctl2.s.rodt_ctl, imp_values->rodt_ohms[lmc_comp_ctl2.s.rodt_ctl]);
David Hendricks2004b932018-03-09 13:58:27 -08006747
David Hendricks7d48ac52018-03-09 14:30:38 -08006748 ////////////////// this is the start of the RANK MAJOR LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006749
David Hendricks7d48ac52018-03-09 14:30:38 -08006750 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
6751 int best_rank_score = DEFAULT_BEST_RANK_SCORE; /* Start with an arbitrarily high score */
6752 int best_rank_rtt_nom = 0;
6753 //int best_rank_nom_ohms = 0;
6754 int best_rank_ctl = 0;
6755 int best_rank_ohms = 0;
6756 int best_rankx = 0;
David Hendricks2004b932018-03-09 13:58:27 -08006757
David Hendricks7d48ac52018-03-09 14:30:38 -08006758 if (!(rank_mask & (1 << rankx)))
6759 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006760
6761 /* Use the delays associated with the best score for each individual rank */
6762 VB_PRT(VBL_TME, "Evaluating Read-Leveling Scoreboard for Rank %d settings.\n", rankx);
6763
David Hendricks7d48ac52018-03-09 14:30:38 -08006764 // some of the rank-related loops below need to operate only on the ranks of a single DIMM,
6765 // so create a mask for their use here
6766 int dimm_rank_mask;
6767 if (num_ranks == 4)
6768 dimm_rank_mask = rank_mask; // should be 1111
6769 else {
6770 dimm_rank_mask = rank_mask & 3; // should be 01 or 11
6771 if (rankx >= 2)
6772 dimm_rank_mask <<= 2; // doing a rank on the second DIMM, should be 0100 or 1100
6773 }
6774 debug_print("DIMM rank mask: 0x%x, rank mask: 0x%x, rankx: %d\n", dimm_rank_mask, rank_mask, rankx);
David Hendricks2004b932018-03-09 13:58:27 -08006775
David Hendricks7d48ac52018-03-09 14:30:38 -08006776 ////////////////// this is the start of the BEST ROW SCORE LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006777
David Hendricks7d48ac52018-03-09 14:30:38 -08006778 for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
6779 //int rtt_nom_ohms;
6780 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
6781 //rtt_nom_ohms = imp_values->rtt_nom_ohms[rtt_nom];
David Hendricks2004b932018-03-09 13:58:27 -08006782
David Hendricks7d48ac52018-03-09 14:30:38 -08006783 /* When the read ODT mask is zero the dyn_rtt_nom_mask is
6784 zero than RTT_NOM will not be changing during
6785 read-leveling. Since the value is fixed we only need
6786 to test it once. */
6787 if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
6788 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006789
David Hendricks7d48ac52018-03-09 14:30:38 -08006790 debug_print("N%d.LMC%d.R%d: starting RTT_NOM %d (%d)\n",
6791 node, ddr_interface_num, rankx, rtt_nom, rtt_nom_ohms);
David Hendricks2004b932018-03-09 13:58:27 -08006792
David Hendricks7d48ac52018-03-09 14:30:38 -08006793 for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
6794 int next_ohms = imp_values->rodt_ohms[rodt_ctl];
David Hendricks2004b932018-03-09 13:58:27 -08006795
David Hendricks7d48ac52018-03-09 14:30:38 -08006796 // skip RODT rows in mask, but *NOT* rows with too high a score;
6797 // we will not use the skipped ones for printing or evaluating, but
6798 // we need to allow all the non-skipped ones to be candidates for "best"
6799 if (((1 << rodt_ctl) & rodt_row_skip_mask) != 0) {
6800 debug_print("N%d.LMC%d.R%d: SKIPPING rodt:%d (%d) with rank_score:%d\n",
6801 node, ddr_interface_num, rankx, rodt_ctl, next_ohms, next_score);
6802 continue;
6803 }
6804 for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // this is ROFFIX-0528
6805 if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
6806 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006807
David Hendricks7d48ac52018-03-09 14:30:38 -08006808 int next_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
David Hendricks2004b932018-03-09 13:58:27 -08006809
David Hendricks7d48ac52018-03-09 14:30:38 -08006810 if (next_score > best_rank_score) // always skip a higher score
6811 continue;
6812 if (next_score == best_rank_score) { // if scores are equal
6813 if (next_ohms < best_rank_ohms) // always skip lower ohms
6814 continue;
6815 if (next_ohms == best_rank_ohms) { // if same ohms
6816 if (orankx != rankx) // always skip the other rank(s)
6817 continue;
6818 }
6819 // else next_ohms are greater, always choose it
6820 }
6821 // else next_score is less than current best, so always choose it
6822 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: new best score: rank %d, rodt %d(%3d), new best %d, previous best %d(%d)\n",
David Hendricks2004b932018-03-09 13:58:27 -08006823 node, ddr_interface_num, rankx, orankx, rodt_ctl, next_ohms, next_score,
6824 best_rank_score, best_rank_ohms);
David Hendricks7d48ac52018-03-09 14:30:38 -08006825 best_rank_score = next_score;
6826 best_rank_rtt_nom = rtt_nom;
6827 //best_rank_nom_ohms = rtt_nom_ohms;
6828 best_rank_ctl = rodt_ctl;
6829 best_rank_ohms = next_ohms;
6830 best_rankx = orankx;
6831 lmc_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01006832
David Hendricks7d48ac52018-03-09 14:30:38 -08006833 } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
6834 } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
6835 } /* for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08006836
David Hendricks7d48ac52018-03-09 14:30:38 -08006837 ////////////////// this is the end of the BEST ROW SCORE LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006838
David Hendricks7d48ac52018-03-09 14:30:38 -08006839 // DANGER, Will Robinson!! Abort now if we did not find a best score at all...
6840 if (best_rank_score == DEFAULT_BEST_RANK_SCORE) {
6841 error_print("WARNING: no best rank score found for N%d.LMC%d.R%d - resetting node...\n",
6842 node, ddr_interface_num, rankx);
6843 bdk_wait_usec(500000);
6844 bdk_reset_chip(node);
6845 }
David Hendricks2004b932018-03-09 13:58:27 -08006846
6847 // FIXME: relative now, but still arbitrary...
6848 // halve the range if 2 DIMMs unless they are single rank...
David Hendricks7d48ac52018-03-09 14:30:38 -08006849 int MAX_RANK_SCORE = best_rank_score;
David Hendricks2004b932018-03-09 13:58:27 -08006850 MAX_RANK_SCORE += (MAX_RANK_SCORE_LIMIT / ((num_ranks > 1) ? dimm_count : 1));
6851
David Hendricks7d48ac52018-03-09 14:30:38 -08006852 if (!ecc_ena){
6853 lmc_rlevel_rank.cn83xx.byte8 = lmc_rlevel_rank.cn83xx.byte0; /* ECC is not used */
6854 }
David Hendricks2004b932018-03-09 13:58:27 -08006855
David Hendricks7d48ac52018-03-09 14:30:38 -08006856 // at the end, write the best row settings to the current rank
6857 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
6858 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08006859
David Hendricks7d48ac52018-03-09 14:30:38 -08006860 bdk_lmcx_rlevel_rankx_t saved_rlevel_rank;
6861 saved_rlevel_rank.u = lmc_rlevel_rank.u;
David Hendricks2004b932018-03-09 13:58:27 -08006862
David Hendricks7d48ac52018-03-09 14:30:38 -08006863 ////////////////// this is the start of the PRINT LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006864
David Hendricks7d48ac52018-03-09 14:30:38 -08006865 // for pass==0, print current rank, pass==1 print other rank(s)
6866 // this is done because we want to show each ranks RODT values together, not interlaced
David Hendricks2004b932018-03-09 13:58:27 -08006867#if COUNT_RL_CANDIDATES
6868 // keep separates for ranks - pass=0 target rank, pass=1 other rank on DIMM
6869 int mask_skipped[2] = {0,0};
6870 int score_skipped[2] = {0,0};
6871 int selected_rows[2] = {0,0};
6872 int zero_scores[2] = {0,0};
6873#endif /* COUNT_RL_CANDIDATES */
David Hendricks7d48ac52018-03-09 14:30:38 -08006874 for (int pass = 0; pass < 2; pass++ ) {
6875 for (int orankx = 0; orankx < dimm_count * 4; orankx++) {
6876 if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
6877 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006878
David Hendricks7d48ac52018-03-09 14:30:38 -08006879 if (((pass == 0) && (orankx != rankx)) || ((pass != 0) && (orankx == rankx)))
6880 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006881
David Hendricks7d48ac52018-03-09 14:30:38 -08006882 for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
6883 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
6884 if (dyn_rtt_nom_mask == 0) {
David Hendricks2004b932018-03-09 13:58:27 -08006885 print_nom_ohms = -1;
6886 if (rtt_idx != min_rtt_nom_idx)
6887 continue;
6888 } else {
6889 print_nom_ohms = imp_values->rtt_nom_ohms[rtt_nom];
6890 }
6891
David Hendricks7d48ac52018-03-09 14:30:38 -08006892 // cycle through all the RODT values...
6893 for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
6894 bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
6895 int temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
6896 temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
David Hendricks2004b932018-03-09 13:58:27 -08006897
David Hendricks7d48ac52018-03-09 14:30:38 -08006898 // skip RODT rows in mask, or rows with too high a score;
6899 // we will not use them for printing or evaluating...
David Hendricks2004b932018-03-09 13:58:27 -08006900#if COUNT_RL_CANDIDATES
David Hendricks7d48ac52018-03-09 14:30:38 -08006901 int skip_row;
David Hendricks2004b932018-03-09 13:58:27 -08006902 if ((1 << rodt_ctl) & rodt_row_skip_mask) {
6903 skip_row = WITH_RODT_SKIPPING;
6904 ++mask_skipped[pass];
6905 } else if (temp_score > MAX_RANK_SCORE) {
6906 skip_row = WITH_RODT_SKIPPING;
6907 ++score_skipped[pass];
6908 } else {
6909 skip_row = WITH_RODT_BLANK;
6910 ++selected_rows[pass];
6911 if (temp_score == 0)
6912 ++zero_scores[pass];
6913 }
David Hendricks7d48ac52018-03-09 14:30:38 -08006914
David Hendricks2004b932018-03-09 13:58:27 -08006915#else /* COUNT_RL_CANDIDATES */
David Hendricks7d48ac52018-03-09 14:30:38 -08006916 int skip_row = (((1 << rodt_ctl) & rodt_row_skip_mask) || (temp_score > MAX_RANK_SCORE))
6917 ? WITH_RODT_SKIPPING: WITH_RODT_BLANK;
David Hendricks2004b932018-03-09 13:58:27 -08006918#endif /* COUNT_RL_CANDIDATES */
6919
6920 // identify and print the BEST ROW when it comes up
6921 if ((skip_row == WITH_RODT_BLANK) &&
6922 (best_rankx == orankx) &&
6923 (best_rank_rtt_nom == rtt_nom) &&
6924 (best_rank_ctl == rodt_ctl))
6925 {
6926 skip_row = WITH_RODT_BESTROW;
6927 }
6928
David Hendricks7d48ac52018-03-09 14:30:38 -08006929 display_RL_with_RODT(node, ddr_interface_num,
6930 temp_rlevel_rank, orankx, temp_score,
6931 print_nom_ohms,
6932 imp_values->rodt_ohms[rodt_ctl],
6933 skip_row);
David Hendricks2004b932018-03-09 13:58:27 -08006934
David Hendricks7d48ac52018-03-09 14:30:38 -08006935 } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
6936 } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
6937 } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) { */
6938 } /* for (int pass = 0; pass < 2; pass++ ) */
David Hendricks2004b932018-03-09 13:58:27 -08006939#if COUNT_RL_CANDIDATES
6940 VB_PRT(VBL_TME, "N%d.LMC%d.R%d: RLROWS: selected %d+%d, zero_scores %d+%d, mask_skipped %d+%d, score_skipped %d+%d\n",
6941 node, ddr_interface_num, rankx,
6942 selected_rows[0], selected_rows[1],
6943 zero_scores[0], zero_scores[1],
6944 mask_skipped[0], mask_skipped[1],
6945 score_skipped[0], score_skipped[1]);
6946#endif /* COUNT_RL_CANDIDATES */
6947
David Hendricks7d48ac52018-03-09 14:30:38 -08006948 ////////////////// this is the end of the PRINT LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006949
David Hendricks7d48ac52018-03-09 14:30:38 -08006950 // now evaluate which bytes need adjusting
6951 uint64_t byte_msk = 0x3f; // 6-bit fields
6952 uint64_t best_byte, new_byte, temp_byte, orig_best_byte;
David Hendricks2004b932018-03-09 13:58:27 -08006953
David Hendricks7d48ac52018-03-09 14:30:38 -08006954 uint64_t rank_best_bytes[9]; // collect the new byte values; first init with current best for neighbor use
6955 for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
6956 rank_best_bytes[byte_idx] = (lmc_rlevel_rank.u >> byte_sh) & byte_msk;
6957 }
David Hendricks2004b932018-03-09 13:58:27 -08006958
David Hendricks7d48ac52018-03-09 14:30:38 -08006959 ////////////////// this is the start of the BEST BYTE LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006960
David Hendricks7d48ac52018-03-09 14:30:38 -08006961 for (int byte_idx = 0, byte_sh = 0; byte_idx < 8+ecc_ena; byte_idx++, byte_sh += 6) {
6962 best_byte = orig_best_byte = rank_best_bytes[byte_idx];
David Hendricks2004b932018-03-09 13:58:27 -08006963
David Hendricks7d48ac52018-03-09 14:30:38 -08006964 ////////////////// this is the start of the BEST BYTE AVERAGING LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006965
David Hendricks7d48ac52018-03-09 14:30:38 -08006966 // validate the initial "best" byte by looking at the average of the unskipped byte-column entries
6967 // we want to do this before we go further, so we can try to start with a better initial value
6968 // this is the so-called "BESTBUY" patch set
6969 int sum = 0, count = 0;
David Hendricks2004b932018-03-09 13:58:27 -08006970
David Hendricks7d48ac52018-03-09 14:30:38 -08006971 for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
6972 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
6973 if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
6974 continue;
David Hendricks2004b932018-03-09 13:58:27 -08006975
David Hendricks7d48ac52018-03-09 14:30:38 -08006976 for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
6977 bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
6978 int temp_score;
6979 for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // average over all the ranks
6980 if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
6981 continue;
6982 temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
6983 // skip RODT rows in mask, or rows with too high a score;
6984 // we will not use them for printing or evaluating...
David Hendricks2004b932018-03-09 13:58:27 -08006985
David Hendricks7d48ac52018-03-09 14:30:38 -08006986 if (!((1 << rodt_ctl) & rodt_row_skip_mask) &&
6987 (temp_score <= MAX_RANK_SCORE))
6988 {
6989 temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
6990 temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
6991 sum += temp_byte;
6992 count++;
6993 }
6994 } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
6995 } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
6996 } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08006997
David Hendricks7d48ac52018-03-09 14:30:38 -08006998 ////////////////// this is the end of the BEST BYTE AVERAGING LOOP
David Hendricks2004b932018-03-09 13:58:27 -08006999
7000
David Hendricks7d48ac52018-03-09 14:30:38 -08007001 uint64_t avg_byte = divide_nint(sum, count); // FIXME: validate count and sum??
7002 int avg_diff = (int)best_byte - (int)avg_byte;
7003 new_byte = best_byte;
7004 if (avg_diff != 0) {
7005 // bump best up/dn by 1, not necessarily all the way to avg
7006 new_byte = best_byte + ((avg_diff > 0) ? -1: 1);
7007 }
David Hendricks2004b932018-03-09 13:58:27 -08007008
David Hendricks7d48ac52018-03-09 14:30:38 -08007009 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: START: Byte %d: best %d is different by %d from average %d, using %d.\n",
7010 node, ddr_interface_num, rankx,
7011 byte_idx, (int)best_byte, avg_diff, (int)avg_byte, (int)new_byte);
7012 best_byte = new_byte;
David Hendricks2004b932018-03-09 13:58:27 -08007013
David Hendricks7d48ac52018-03-09 14:30:38 -08007014 // At this point best_byte is either:
7015 // 1. the original byte-column value from the best scoring RODT row, OR
7016 // 2. that value bumped toward the average of all the byte-column values
7017 //
7018 // best_byte will not change from here on...
David Hendricks2004b932018-03-09 13:58:27 -08007019
David Hendricks7d48ac52018-03-09 14:30:38 -08007020 ////////////////// this is the start of the BEST BYTE COUNTING LOOP
David Hendricks2004b932018-03-09 13:58:27 -08007021
David Hendricks7d48ac52018-03-09 14:30:38 -08007022 // NOTE: we do this next loop separately from above, because we count relative to "best_byte"
7023 // which may have been modified by the above averaging operation...
David Hendricks2004b932018-03-09 13:58:27 -08007024 //
7025 // Also, the above only moves toward the average by +- 1, so that we will always have a count
7026 // of at least 1 for the original best byte, even if all the others are further away and not counted;
7027 // this ensures we will go back to the original if no others are counted...
7028 // FIXME: this could cause issue if the range of values for a byte-lane are too disparate...
David Hendricks7d48ac52018-03-09 14:30:38 -08007029 int count_less = 0, count_same = 0, count_more = 0;
David Hendricks2004b932018-03-09 13:58:27 -08007030#if FAILSAFE_CHECK
7031 uint64_t count_byte = new_byte; // save the value we will count around
7032#endif /* FAILSAFE_CHECK */
7033#if RANK_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08007034 int rank_less = 0, rank_same = 0, rank_more = 0;
David Hendricks2004b932018-03-09 13:58:27 -08007035#endif /* RANK_MAJORITY */
7036
David Hendricks7d48ac52018-03-09 14:30:38 -08007037 for (rtt_idx = min_rtt_nom_idx; rtt_idx <= max_rtt_nom_idx; ++rtt_idx) {
7038 rtt_nom = imp_values->rtt_nom_table[rtt_idx];
7039 if ((dyn_rtt_nom_mask == 0) && (rtt_idx != min_rtt_nom_idx))
7040 continue;
David Hendricks2004b932018-03-09 13:58:27 -08007041
David Hendricks7d48ac52018-03-09 14:30:38 -08007042 for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) {
7043 bdk_lmcx_rlevel_rankx_t temp_rlevel_rank;
7044 int temp_score;
7045 for (int orankx = 0; orankx < dimm_count * 4; orankx++) { // count over all the ranks
7046 if (!(dimm_rank_mask & (1 << orankx))) // stay on the same DIMM
7047 continue;
7048 temp_score = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].score;
7049 // skip RODT rows in mask, or rows with too high a score;
7050 // we will not use them for printing or evaluating...
7051 if (((1 << rodt_ctl) & rodt_row_skip_mask) ||
7052 (temp_score > MAX_RANK_SCORE))
7053 {
7054 continue;
7055 }
7056 temp_rlevel_rank.u = rlevel_scoreboard[rtt_nom][rodt_ctl][orankx].setting;
7057 temp_byte = (temp_rlevel_rank.u >> byte_sh) & byte_msk;
David Hendricks2004b932018-03-09 13:58:27 -08007058
David Hendricks7d48ac52018-03-09 14:30:38 -08007059 if (temp_byte == 0) // do not count it if illegal
7060 continue;
7061 else if (temp_byte == best_byte)
7062 count_same++;
7063 else if (temp_byte == best_byte - 1)
7064 count_less++;
7065 else if (temp_byte == best_byte + 1)
7066 count_more++;
7067 // else do not count anything more than 1 away from the best
David Hendricks2004b932018-03-09 13:58:27 -08007068#if RANK_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08007069 // FIXME? count is relative to best_byte; should it be rank-based?
7070 if (orankx != rankx) // rank counts only on main rank
7071 continue;
7072 else if (temp_byte == best_byte)
7073 rank_same++;
7074 else if (temp_byte == best_byte - 1)
7075 rank_less++;
7076 else if (temp_byte == best_byte + 1)
7077 rank_more++;
David Hendricks2004b932018-03-09 13:58:27 -08007078#endif /* RANK_MAJORITY */
David Hendricks7d48ac52018-03-09 14:30:38 -08007079 } /* for (int orankx = 0; orankx < dimm_count * 4; orankx++) */
7080 } /* for (rodt_ctl = max_rodt_ctl; rodt_ctl >= min_rodt_ctl; --rodt_ctl) */
7081 } /* for (rtt_idx=min_rtt_nom_idx; rtt_idx<=max_rtt_nom_idx; ++rtt_idx) */
David Hendricks2004b932018-03-09 13:58:27 -08007082
7083#if RANK_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08007084 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d (%d/%d/%d)\n",
7085 node, ddr_interface_num, rankx,
7086 byte_idx, (int)orig_best_byte, (int)best_byte,
7087 count_more, count_same, count_less,
7088 rank_more, rank_same, rank_less);
David Hendricks2004b932018-03-09 13:58:27 -08007089#else /* RANK_MAJORITY */
David Hendricks7d48ac52018-03-09 14:30:38 -08007090 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: COUNT: Byte %d: orig %d now %d, more %d same %d less %d\n",
7091 node, ddr_interface_num, rankx,
7092 byte_idx, (int)orig_best_byte, (int)best_byte,
7093 count_more, count_same, count_less);
David Hendricks2004b932018-03-09 13:58:27 -08007094#endif /* RANK_MAJORITY */
David Hendricks7d48ac52018-03-09 14:30:38 -08007095 ////////////////// this is the end of the BEST BYTE COUNTING LOOP
David Hendricks2004b932018-03-09 13:58:27 -08007096
David Hendricks7d48ac52018-03-09 14:30:38 -08007097 // choose the new byte value
7098 // we need to check that there is no gap greater than 2 between adjacent bytes
7099 // (adjacency depends on DIMM type)
7100 // use the neighbor value to help decide
7101 // initially, the rank_best_bytes[] will contain values from the chosen lowest score rank
7102 new_byte = 0;
David Hendricks2004b932018-03-09 13:58:27 -08007103
David Hendricks7d48ac52018-03-09 14:30:38 -08007104 // neighbor is index-1 unless we are index 0 or index 8 (ECC)
7105 int neighbor = (byte_idx == 8) ? 3 : ((byte_idx == 0) ? 1 : byte_idx - 1);
7106 uint64_t neigh_byte = rank_best_bytes[neighbor];
David Hendricks2004b932018-03-09 13:58:27 -08007107
7108
David Hendricks7d48ac52018-03-09 14:30:38 -08007109 // can go up or down or stay the same, so look at a numeric average to help
7110 new_byte = divide_nint(((count_more * (best_byte + 1)) +
7111 (count_same * (best_byte + 0)) +
7112 (count_less * (best_byte - 1))),
7113 max(1, (count_more + count_same + count_less)));
David Hendricks2004b932018-03-09 13:58:27 -08007114
David Hendricks7d48ac52018-03-09 14:30:38 -08007115 // use neighbor to help choose with average
7116 if ((byte_idx > 0) && (_abs(neigh_byte - new_byte) > 2)) // but not for byte 0
7117 {
7118 uint64_t avg_pick = new_byte;
7119 if ((new_byte - best_byte) != 0)
7120 new_byte = best_byte; // back to best, average did not get better
7121 else // avg was the same, still too far, now move it towards the neighbor
7122 new_byte += (neigh_byte > new_byte) ? 1 : -1;
David Hendricks2004b932018-03-09 13:58:27 -08007123
David Hendricks7d48ac52018-03-09 14:30:38 -08007124 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: neighbor %d too different %d from average %d, picking %d.\n",
7125 node, ddr_interface_num, rankx,
7126 byte_idx, neighbor, (int)neigh_byte, (int)avg_pick, (int)new_byte);
7127 }
David Hendricks2004b932018-03-09 13:58:27 -08007128#if MAJORITY_OVER_AVG
David Hendricks7d48ac52018-03-09 14:30:38 -08007129 // NOTE:
7130 // For now, we let the neighbor processing above trump the new simple majority processing here.
7131 // This is mostly because we have seen no smoking gun for a neighbor bad choice (yet?).
7132 // Also note that we will ALWAYS be using byte 0 majority, because of the if clause above.
7133 else {
7134 // majority is dependent on the counts, which are relative to best_byte, so start there
7135 uint64_t maj_byte = best_byte;
7136 if ((count_more > count_same) && (count_more > count_less)) {
7137 maj_byte++;
7138 } else if ((count_less > count_same) && (count_less > count_more)) {
7139 maj_byte--;
7140 }
7141 if (maj_byte != new_byte) {
7142 // print only when majority choice is different from average
7143 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: MAJORTY: Byte %d: picking majority of %d over average %d.\n",
7144 node, ddr_interface_num, rankx,
7145 byte_idx, (int)maj_byte, (int)new_byte);
7146 new_byte = maj_byte;
7147 } else {
7148 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
7149 node, ddr_interface_num, rankx,
7150 byte_idx, (int)new_byte);
7151 }
David Hendricks2004b932018-03-09 13:58:27 -08007152#if RANK_MAJORITY
David Hendricks7d48ac52018-03-09 14:30:38 -08007153 // rank majority is dependent on the rank counts, which are relative to best_byte,
7154 // so start there, and adjust according to the rank counts majority
7155 uint64_t rank_maj = best_byte;
7156 if ((rank_more > rank_same) && (rank_more > rank_less)) {
7157 rank_maj++;
7158 } else if ((rank_less > rank_same) && (rank_less > rank_more)) {
7159 rank_maj--;
7160 }
7161 int rank_sum = rank_more + rank_same + rank_less;
David Hendricks2004b932018-03-09 13:58:27 -08007162
David Hendricks7d48ac52018-03-09 14:30:38 -08007163 // now, let rank majority possibly rule over the current new_byte however we got it
7164 if (rank_maj != new_byte) { // only if different
7165 // Here is where we decide whether to completely apply RANK_MAJORITY or not
7166 // FIXME: For the moment, we do it ONLY when running 2-slot configs
7167 // FIXME? or when rank_sum is big enough?
7168 if ((dimm_count > 1) || (rank_sum > 2)) {
7169 // print only when rank majority choice is selected
7170 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: picking %d over %d.\n",
7171 node, ddr_interface_num, rankx,
7172 byte_idx, (int)rank_maj, (int)new_byte);
7173 new_byte = rank_maj;
7174 } else { // FIXME: print some info when we could have chosen RANKMAJ but did not
7175 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: RANKMAJ: Byte %d: NOT using %d over %d (best=%d,sum=%d).\n",
7176 node, ddr_interface_num, rankx,
7177 byte_idx, (int)rank_maj, (int)new_byte,
7178 (int)best_byte, rank_sum);
7179 }
7180 }
David Hendricks2004b932018-03-09 13:58:27 -08007181#endif /* RANK_MAJORITY */
David Hendricks7d48ac52018-03-09 14:30:38 -08007182 }
David Hendricks2004b932018-03-09 13:58:27 -08007183#else
David Hendricks7d48ac52018-03-09 14:30:38 -08007184 else {
7185 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: AVERAGE: Byte %d: picking average of %d.\n",
7186 node, ddr_interface_num, rankx,
7187 byte_idx, (int)new_byte);
7188 }
David Hendricks2004b932018-03-09 13:58:27 -08007189#endif
7190#if FAILSAFE_CHECK
7191 // one last check:
7192 // if new_byte is still count_byte, BUT there was no count for that value, DO SOMETHING!!!
7193 // FIXME: go back to original best byte from the best row
7194 if ((new_byte == count_byte) && (count_same == 0)) {
7195 new_byte = orig_best_byte;
David Hendricks7d48ac52018-03-09 14:30:38 -08007196 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: FAILSAF: Byte %d: going back to original %d.\n",
7197 node, ddr_interface_num, rankx,
7198 byte_idx, (int)new_byte);
David Hendricks2004b932018-03-09 13:58:27 -08007199 }
7200#endif /* FAILSAFE_CHECK */
7201#if PERFECT_BITMASK_COUNTING
7202 // Look at counts for "perfect" bitmasks if we had any for this byte-lane.
7203 // Remember, we only counted for DDR4, so zero means none or DDR3, and we bypass this...
7204 if (rank_perfect_counts[rankx].total[byte_idx] > 0) {
7205 // FIXME: should be more error checking, look for ties, etc...
David Hendricks7d48ac52018-03-09 14:30:38 -08007206 /* FIXME(dhendrix): i shadows another local variable, changed to _i in this block */
7207// int i, delay_count, delay_value, delay_max;
7208 int _i, delay_count, delay_value, delay_max;
David Hendricks2004b932018-03-09 13:58:27 -08007209 uint32_t ties;
7210 delay_value = -1;
7211 delay_max = 0;
7212 ties = 0;
7213
David Hendricks7d48ac52018-03-09 14:30:38 -08007214 for (_i = 0; _i < 32; _i++) {
7215 delay_count = rank_perfect_counts[rankx].count[byte_idx][_i];
David Hendricks2004b932018-03-09 13:58:27 -08007216 if (delay_count > 0) { // only look closer if there are any,,,
7217 if (delay_count > delay_max) {
7218 delay_max = delay_count;
David Hendricks7d48ac52018-03-09 14:30:38 -08007219 delay_value = _i;
David Hendricks2004b932018-03-09 13:58:27 -08007220 ties = 0; // reset ties to none
7221 } else if (delay_count == delay_max) {
7222 if (ties == 0)
7223 ties = 1UL << delay_value; // put in original value
David Hendricks7d48ac52018-03-09 14:30:38 -08007224 ties |= 1UL << _i; // add new value
David Hendricks2004b932018-03-09 13:58:27 -08007225 }
7226 }
David Hendricks7d48ac52018-03-09 14:30:38 -08007227 } /* for (_i = 0; _i < 32; _i++) */
David Hendricks2004b932018-03-09 13:58:27 -08007228
7229 if (delay_value >= 0) {
7230 if (ties != 0) {
7231 if (ties & (1UL << (int)new_byte)) {
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007232 // leave choice as new_byte if any tied one is the same...
David Hendricks2004b932018-03-09 13:58:27 -08007233
7234
7235 delay_value = (int)new_byte;
7236 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: PERFECT: Byte %d: TIES (0x%x) INCLUDED %d (%d)\n",
7237 node, ddr_interface_num, rankx, byte_idx, ties, (int)new_byte, delay_max);
7238 } else {
7239 // FIXME: should choose a perfect one!!!
7240 // FIXME: for now, leave the choice as new_byte
7241 delay_value = (int)new_byte;
7242 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: PERFECT: Byte %d: TIES (0x%x) OMITTED %d (%d)\n",
7243 node, ddr_interface_num, rankx, byte_idx, ties, (int)new_byte, delay_max);
7244 }
7245 } /* if (ties != 0) */
7246
7247 if (delay_value != (int)new_byte) {
7248 delay_count = rank_perfect_counts[rankx].count[byte_idx][(int)new_byte];
7249 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: PERFECT: Byte %d: DIFF from %d (%d), USING %d (%d)\n",
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007250 node, ddr_interface_num, rankx, byte_idx, (int)new_byte,
David Hendricks2004b932018-03-09 13:58:27 -08007251 delay_count, delay_value, delay_max);
7252 new_byte = (uint64_t)delay_value; // FIXME: make this optional via envvar?
7253 } else {
7254 debug_print("N%d.LMC%d.R%d: PERFECT: Byte %d: SAME as %d (%d)\n",
7255 node, ddr_interface_num, rankx, byte_idx, new_byte, delay_max);
7256 }
7257 }
7258 } /* if (rank_perfect_counts[rankx].total[byte_idx] > 0) */
7259 else {
7260 if (ddr_type == DDR4_DRAM) { // only report when DDR4
7261 // FIXME: remove or increase VBL for this output...
7262 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: PERFECT: Byte %d: ZERO perfect bitmasks\n",
7263 node, ddr_interface_num, rankx, byte_idx);
7264 }
7265 } /* if (rank_perfect_counts[rankx].total[byte_idx] > 0) */
7266#endif /* PERFECT_BITMASK_COUNTING */
7267
David Hendricks7d48ac52018-03-09 14:30:38 -08007268 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SUMMARY: Byte %d: %s: orig %d now %d, more %d same %d less %d, using %d\n",
7269 node, ddr_interface_num, rankx,
7270 byte_idx, "AVG", (int)orig_best_byte,
7271 (int)best_byte, count_more, count_same, count_less, (int)new_byte);
David Hendricks2004b932018-03-09 13:58:27 -08007272
David Hendricks7d48ac52018-03-09 14:30:38 -08007273 // update the byte with the new value (NOTE: orig value in the CSR may not be current "best")
7274 lmc_rlevel_rank.u &= ~(byte_msk << byte_sh);
7275 lmc_rlevel_rank.u |= (new_byte << byte_sh);
David Hendricks2004b932018-03-09 13:58:27 -08007276
David Hendricks7d48ac52018-03-09 14:30:38 -08007277 rank_best_bytes[byte_idx] = new_byte; // save new best for neighbor use
David Hendricks2004b932018-03-09 13:58:27 -08007278
David Hendricks7d48ac52018-03-09 14:30:38 -08007279 } /* for (byte_idx = 0; byte_idx < 8+ecc_ena; byte_idx++) */
David Hendricks2004b932018-03-09 13:58:27 -08007280
David Hendricks7d48ac52018-03-09 14:30:38 -08007281 ////////////////// this is the end of the BEST BYTE LOOP
David Hendricks2004b932018-03-09 13:58:27 -08007282
David Hendricks7d48ac52018-03-09 14:30:38 -08007283 if (saved_rlevel_rank.u != lmc_rlevel_rank.u) {
7284 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
7285 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
7286 debug_print("Adjusting Read-Leveling per-RANK settings.\n");
7287 } else {
7288 debug_print("Not Adjusting Read-Leveling per-RANK settings.\n");
7289 }
7290 display_RL_with_final(node, ddr_interface_num, lmc_rlevel_rank, rankx);
David Hendricks2004b932018-03-09 13:58:27 -08007291
7292#if RLEXTRAS_PATCH
7293#define RLEVEL_RANKX_EXTRAS_INCR 4
David Hendricks7d48ac52018-03-09 14:30:38 -08007294 if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
7295 bdk_lmcx_rlevel_rankx_t temp_rlevel_rank = lmc_rlevel_rank; // copy the current rank
7296 int byte, delay;
7297 if (rankx < 3) {
7298 debug_print("N%d.LMC%d.R%d: checking for RLEVEL_RANK unused entries.\n",
7299 node, ddr_interface_num, rankx);
7300 for (byte = 0; byte < 9; byte++) { // modify the copy in prep for writing to empty slot(s)
7301 delay = get_rlevel_rank_struct(&temp_rlevel_rank, byte) + RLEVEL_RANKX_EXTRAS_INCR;
7302 if (delay > (int)RLEVEL_BYTE_MSK) delay = RLEVEL_BYTE_MSK;
7303 update_rlevel_rank_struct(&temp_rlevel_rank, byte, delay);
7304 }
7305 if (rankx == 0) { // if rank 0, write rank 1 and rank 2 here if empty
7306 if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
7307 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
7308 node, ddr_interface_num, rankx, 1);
7309 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 1), temp_rlevel_rank.u);
7310 }
7311 if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
7312 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
7313 node, ddr_interface_num, rankx, 2);
7314 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 2), temp_rlevel_rank.u);
7315 }
7316 }
7317 // if ranks 0, 1 or 2, write rank 3 here if empty
7318 if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
7319 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing RLEVEL_RANK unused entry R%d.\n",
7320 node, ddr_interface_num, rankx, 3);
7321 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, 3), temp_rlevel_rank.u);
7322 }
7323 }
7324 }
David Hendricks2004b932018-03-09 13:58:27 -08007325#endif /* RLEXTRAS_PATCH */
David Hendricks7d48ac52018-03-09 14:30:38 -08007326 } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
David Hendricks2004b932018-03-09 13:58:27 -08007327
David Hendricks7d48ac52018-03-09 14:30:38 -08007328 ////////////////// this is the end of the RANK MAJOR LOOP
David Hendricks2004b932018-03-09 13:58:27 -08007329
David Hendricks7d48ac52018-03-09 14:30:38 -08007330 } /* Evaluation block */
David Hendricks2004b932018-03-09 13:58:27 -08007331 } /* while(rlevel_debug_loops--) */
7332
7333 lmc_control.s.ddr2t = save_ddr2t;
7334 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
7335 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
7336 ddr_print("%-45s : %6d\n", "DDR2T", lmc_control.s.ddr2t); /* Display final 2T value */
7337
7338
7339 perform_ddr_init_sequence(node, rank_mask, ddr_interface_num);
7340
7341 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
7342 uint64_t value;
7343 int parameter_set = 0;
7344 if (!(rank_mask & (1 << rankx)))
7345 continue;
7346
7347 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
7348
7349 for (i=0; i<9; ++i) {
7350 if ((s = lookup_env_parameter("ddr%d_rlevel_rank%d_byte%d", ddr_interface_num, rankx, i)) != NULL) {
7351 parameter_set |= 1;
7352 value = strtoul(s, NULL, 0);
7353
7354 update_rlevel_rank_struct(&lmc_rlevel_rank, i, value);
7355 }
7356 }
7357
7358 if ((s = lookup_env_parameter_ull("ddr%d_rlevel_rank%d", ddr_interface_num, rankx)) != NULL) {
7359 parameter_set |= 1;
7360 value = strtoull(s, NULL, 0);
7361 lmc_rlevel_rank.u = value;
7362 }
7363
David Hendricks2004b932018-03-09 13:58:27 -08007364 if (parameter_set) {
7365 DRAM_CSR_WRITE(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx), lmc_rlevel_rank.u);
7366 display_RL(node, ddr_interface_num, lmc_rlevel_rank, rankx);
7367 }
7368 }
7369 }
7370
7371 /* Workaround Trcd overflow by using Additive latency. */
7372 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
7373 {
7374 bdk_lmcx_modereg_params0_t lmc_modereg_params0;
7375 bdk_lmcx_timing_params1_t lmc_timing_params1;
7376 bdk_lmcx_control_t lmc_control;
7377 int rankx;
7378
7379 lmc_timing_params1.u = BDK_CSR_READ(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num));
7380 lmc_modereg_params0.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num));
7381 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
7382
7383 if (lmc_timing_params1.s.trcd == 0) {
7384 ddr_print("Workaround Trcd overflow by using Additive latency.\n");
7385 lmc_timing_params1.s.trcd = 12; /* Hard code this to 12 and enable additive latency */
7386 lmc_modereg_params0.s.al = 2; /* CL-2 */
7387 lmc_control.s.pocas = 1;
7388
David Hendricks7d48ac52018-03-09 14:30:38 -08007389 ddr_print("MODEREG_PARAMS0 : 0x%016llx\n", lmc_modereg_params0.u);
David Hendricks2004b932018-03-09 13:58:27 -08007390 DRAM_CSR_WRITE(node, BDK_LMCX_MODEREG_PARAMS0(ddr_interface_num), lmc_modereg_params0.u);
David Hendricks7d48ac52018-03-09 14:30:38 -08007391 ddr_print("TIMING_PARAMS1 : 0x%016llx\n", lmc_timing_params1.u);
David Hendricks2004b932018-03-09 13:58:27 -08007392 DRAM_CSR_WRITE(node, BDK_LMCX_TIMING_PARAMS1(ddr_interface_num), lmc_timing_params1.u);
7393
David Hendricks7d48ac52018-03-09 14:30:38 -08007394 ddr_print("LMC_CONTROL : 0x%016llx\n", lmc_control.u);
David Hendricks2004b932018-03-09 13:58:27 -08007395 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
7396
7397 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
7398 if (!(rank_mask & (1 << rankx)))
7399 continue;
7400
7401 ddr4_mrw(node, ddr_interface_num, rankx, -1, 1, 0); /* MR1 */
7402 }
7403 }
7404 }
7405
7406 // this is here just for output, to allow check of the Deskew settings one last time...
7407 if (! disable_deskew_training) {
7408 deskew_counts_t dsk_counts;
David Hendricks7d48ac52018-03-09 14:30:38 -08007409 VB_PRT(VBL_TME, "N%d.LMC%d: Check Deskew Settings before software Write-Leveling.\n",
7410 node, ddr_interface_num);
David Hendricks2004b932018-03-09 13:58:27 -08007411 Validate_Read_Deskew_Training(node, rank_mask, ddr_interface_num, &dsk_counts, VBL_TME); // TME for FINAL
7412 }
7413
7414
7415 /* Workaround Errata 26304 (T88@2.0)
7416
7417 When the CSRs LMCX_DLL_CTL3[WR_DESKEW_ENA] = 1 AND
7418 LMCX_PHY_CTL2[DQS[0..8]_DSK_ADJ] > 4, set
7419 LMCX_EXT_CONFIG[DRIVE_ENA_BPRCH] = 1.
7420 */
7421 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS2_X)) { // only for 88XX pass 2, not 81xx or 83xx
7422 bdk_lmcx_dll_ctl3_t dll_ctl3;
7423 bdk_lmcx_phy_ctl2_t phy_ctl2;
7424 bdk_lmcx_ext_config_t ext_config;
7425 int increased_dsk_adj = 0;
7426 int byte;
7427
7428 phy_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_PHY_CTL2(ddr_interface_num));
7429 ext_config.u = BDK_CSR_READ(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num));
7430 dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
7431
7432 for (byte = 0; byte < 8; ++byte) {
7433 if (!(ddr_interface_bytemask&(1<<byte)))
7434 continue;
7435 increased_dsk_adj |= (((phy_ctl2.u >> (byte*3)) & 0x7) > 4);
7436 }
7437
7438 if ((dll_ctl3.s.wr_deskew_ena == 1) && increased_dsk_adj) {
7439 ext_config.s.drive_ena_bprch = 1;
7440 DRAM_CSR_WRITE(node, BDK_LMCX_EXT_CONFIG(ddr_interface_num),
7441 ext_config.u);
7442 }
7443 }
7444
7445 /*
7446 * 6.9.13 DRAM Vref Training for DDR4
7447 *
7448 * This includes software write-leveling
7449 */
7450
7451 { // Software Write-Leveling block
7452
7453 /* Try to determine/optimize write-level delays experimentally. */
7454#pragma pack(push,1)
7455 bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank;
7456 bdk_lmcx_wlevel_rankx_t lmc_wlevel_rank_hw_results;
7457 int byte;
7458 int delay;
7459 int rankx = 0;
7460 int active_rank;
7461#if !DISABLE_SW_WL_PASS_2
7462 bdk_lmcx_rlevel_rankx_t lmc_rlevel_rank;
7463 int sw_wlevel_offset = 1;
7464#endif
7465 int sw_wlevel_enable = 1; /* FIX... Should be customizable. */
7466 int interfaces;
David Hendricks7d48ac52018-03-09 14:30:38 -08007467 int measured_vref_flag;
David Hendricks2004b932018-03-09 13:58:27 -08007468 typedef enum {
7469 WL_ESTIMATED = 0, /* HW/SW wleveling failed. Results
7470 estimated. */
7471 WL_HARDWARE = 1, /* H/W wleveling succeeded */
7472 WL_SOFTWARE = 2, /* S/W wleveling passed 2 contiguous
7473 settings. */
7474 WL_SOFTWARE1 = 3, /* S/W wleveling passed 1 marginal
7475 setting. */
7476 } sw_wl_status_t;
7477
7478 static const char *wl_status_strings[] = {
7479 "(e)",
7480 " ",
7481 " ",
7482 "(1)"
7483 };
7484 int sw_wlevel_hw_default = 1; // FIXME: make H/W assist the default now
7485#pragma pack(pop)
7486
7487 if ((s = lookup_env_parameter("ddr_sw_wlevel_hw")) != NULL) {
7488 sw_wlevel_hw_default = !!strtoul(s, NULL, 0);
7489 }
7490
7491 // cannot use hw-assist when doing 32-bit
7492 if (! ddr_interface_64b) {
7493 sw_wlevel_hw_default = 0;
7494 }
7495
7496 if ((s = lookup_env_parameter("ddr_software_wlevel")) != NULL) {
7497 sw_wlevel_enable = strtoul(s, NULL, 0);
7498 }
7499
7500#if SWL_WITH_HW_ALTS_CHOOSE_SW
7501 // Choose the SW algo for SWL if any HWL alternates were found
7502 // NOTE: we have to do this here, and for all, since HW-assist including ECC requires ECC enable
7503 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
7504 if (!sw_wlevel_enable)
7505 break;
7506 if (!(rank_mask & (1 << rankx)))
7507 continue;
7508
7509 // if we are doing HW-assist, and there are alternates, switch to SW-algorithm for all
7510 if (sw_wlevel_hw && hwl_alts[rankx].hwl_alt_mask) {
7511 ddr_print("N%d.LMC%d.R%d: Using SW algorithm for write-leveling this rank\n",
7512 node, ddr_interface_num, rankx);
7513 sw_wlevel_hw_default = 0;
7514 break;
7515 }
7516 } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
7517#endif
7518
David Hendricks7d48ac52018-03-09 14:30:38 -08007519 /* Get the measured_vref setting from the config, check for an override... */
7520 /* NOTE: measured_vref=1 (ON) means force use of MEASURED Vref... */
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007521 // NOTE: measured VREF can only be done for DDR4
David Hendricks2004b932018-03-09 13:58:27 -08007522 if (ddr_type == DDR4_DRAM) {
7523 measured_vref_flag = custom_lmc_config->measured_vref;
7524 if ((s = lookup_env_parameter("ddr_measured_vref")) != NULL) {
7525 measured_vref_flag = !!strtoul(s, NULL, 0);
7526 }
7527 } else {
7528 measured_vref_flag = 0; // OFF for DDR3
7529 }
7530
7531 /* Ensure disabled ECC for DRAM tests using the SW algo, else leave it untouched */
7532 if (!sw_wlevel_hw_default) {
7533 lmc_config.u = BDK_CSR_READ(node, BDK_LMCX_CONFIG(ddr_interface_num));
7534 lmc_config.s.ecc_ena = 0;
7535 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
7536 }
7537
7538#if USE_L2_WAYS_LIMIT
7539 limit_l2_ways(node, 0, 0); /* Disable l2 sets for DRAM testing */
7540#endif
7541
7542 /* We need to track absolute rank number, as well as how many
7543 ** active ranks we have. Two single rank DIMMs show up as
7544 ** ranks 0 and 2, but only 2 ranks are active. */
7545 active_rank = 0;
7546
David Hendricks7d48ac52018-03-09 14:30:38 -08007547 interfaces = bdk_pop(ddr_interface_mask);
David Hendricks2004b932018-03-09 13:58:27 -08007548
7549#define VREF_RANGE1_LIMIT 0x33 // range1 is valid for 0x00 - 0x32
7550#define VREF_RANGE2_LIMIT 0x18 // range2 is valid for 0x00 - 0x17
7551// full window is valid for 0x00 to 0x4A
7552// let 0x00 - 0x17 be range2, 0x18 - 0x4a be range 1
7553#define VREF_LIMIT (VREF_RANGE1_LIMIT + VREF_RANGE2_LIMIT)
7554#define VREF_FINAL (VREF_LIMIT - 1)
7555
7556 for (rankx = 0; rankx < dimm_count * 4; rankx++) {
7557 uint64_t rank_addr;
7558 int vref_value, final_vref_value, final_vref_range = 0;
David Hendricks7d48ac52018-03-09 14:30:38 -08007559 int start_vref_value = 0, computed_final_vref_value = -1;
David Hendricks2004b932018-03-09 13:58:27 -08007560 char best_vref_values_count, vref_values_count;
7561 char best_vref_values_start, vref_values_start;
7562
7563 int bytes_failed;
7564 sw_wl_status_t byte_test_status[9];
7565 sw_wl_status_t sw_wl_rank_status = WL_HARDWARE;
David Hendricks7d48ac52018-03-09 14:30:38 -08007566 int sw_wl_failed = 0;
David Hendricks2004b932018-03-09 13:58:27 -08007567 int sw_wlevel_hw = sw_wlevel_hw_default;
7568
7569 if (!sw_wlevel_enable)
7570 break;
7571
7572 if (!(rank_mask & (1 << rankx)))
7573 continue;
7574
7575 ddr_print("N%d.LMC%d.R%d: Performing Software Write-Leveling %s\n",
7576 node, ddr_interface_num, rankx,
7577 (sw_wlevel_hw) ? "with H/W assist" : "with S/W algorithm");
7578
David Hendricks7d48ac52018-03-09 14:30:38 -08007579 if ((ddr_type == DDR4_DRAM) && (num_ranks != 4)) {
7580 // always compute when we can...
7581 computed_final_vref_value = compute_vref_value(node, ddr_interface_num, rankx,
7582 dimm_count, num_ranks, imp_values,
7583 is_stacked_die);
7584 if (!measured_vref_flag) // but only use it if allowed
7585 start_vref_value = VREF_FINAL; // skip all the measured Vref processing, just the final setting
7586 }
David Hendricks2004b932018-03-09 13:58:27 -08007587
7588 /* Save off the h/w wl results */
7589 lmc_wlevel_rank_hw_results.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
7590
7591 vref_values_count = 0;
7592 vref_values_start = 0;
7593 best_vref_values_count = 0;
7594 best_vref_values_start = 0;
7595
7596 /* Loop one extra time using the Final Vref value. */
7597 for (vref_value = start_vref_value; vref_value < VREF_LIMIT; ++vref_value) {
7598 if (ddr_type == DDR4_DRAM) {
7599 if (vref_value < VREF_FINAL) {
7600 int vrange, vvalue;
7601 if (vref_value < VREF_RANGE2_LIMIT) {
7602 vrange = 1; vvalue = vref_value;
7603 } else {
7604 vrange = 0; vvalue = vref_value - VREF_RANGE2_LIMIT;
7605 }
David Hendricks7d48ac52018-03-09 14:30:38 -08007606 set_vref(node, ddr_interface_num, rankx,
David Hendricks2004b932018-03-09 13:58:27 -08007607 vrange, vvalue);
7608 } else { /* if (vref_value < VREF_FINAL) */
7609 /* Print the final Vref value first. */
7610
David Hendricks7d48ac52018-03-09 14:30:38 -08007611 /* Always print the computed first if its valid */
7612 if (computed_final_vref_value >= 0) {
7613 ddr_print("N%d.LMC%d.R%d: Vref Computed Summary :"
7614 " %2d (0x%02x)\n",
7615 node, ddr_interface_num,
7616 rankx, computed_final_vref_value,
7617 computed_final_vref_value);
7618 }
7619 if (!measured_vref_flag) { // setup to use the computed
7620 best_vref_values_count = 1;
7621 final_vref_value = computed_final_vref_value;
7622 } else { // setup to use the measured
7623 if (best_vref_values_count > 0) {
7624 best_vref_values_count = max(best_vref_values_count, 2);
David Hendricks2004b932018-03-09 13:58:27 -08007625#if 0
7626 // NOTE: this already adjusts VREF via calculating 40% rather than 50%
David Hendricks7d48ac52018-03-09 14:30:38 -08007627 final_vref_value = best_vref_values_start + divide_roundup((best_vref_values_count-1)*4,10);
7628 ddr_print("N%d.LMC%d.R%d: Vref Training Summary :"
7629 " %2d <----- %2d (0x%02x) -----> %2d range: %2d\n",
7630 node, ddr_interface_num, rankx, best_vref_values_start,
7631 final_vref_value, final_vref_value,
7632 best_vref_values_start+best_vref_values_count-1,
7633 best_vref_values_count-1);
David Hendricks2004b932018-03-09 13:58:27 -08007634#else
David Hendricks7d48ac52018-03-09 14:30:38 -08007635 final_vref_value = best_vref_values_start + divide_nint(best_vref_values_count - 1, 2);
David Hendricks2004b932018-03-09 13:58:27 -08007636 if (final_vref_value < VREF_RANGE2_LIMIT) {
7637 final_vref_range = 1;
7638 } else {
7639 final_vref_range = 0; final_vref_value -= VREF_RANGE2_LIMIT;
7640 }
7641 {
7642 int vvlo = best_vref_values_start;
7643 int vrlo;
7644 if (vvlo < VREF_RANGE2_LIMIT) {
7645 vrlo = 2;
7646 } else {
7647 vrlo = 1; vvlo -= VREF_RANGE2_LIMIT;
7648 }
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007649
David Hendricks2004b932018-03-09 13:58:27 -08007650 int vvhi = best_vref_values_start + best_vref_values_count - 1;
7651 int vrhi;
7652 if (vvhi < VREF_RANGE2_LIMIT) {
7653 vrhi = 2;
7654 } else {
7655 vrhi = 1; vvhi -= VREF_RANGE2_LIMIT;
7656 }
7657 ddr_print("N%d.LMC%d.R%d: Vref Training Summary :"
7658 " 0x%02x/%1d <----- 0x%02x/%1d -----> 0x%02x/%1d, range: %2d\n",
7659 node, ddr_interface_num, rankx,
7660 vvlo, vrlo,
7661 final_vref_value, final_vref_range + 1,
7662 vvhi, vrhi,
7663 best_vref_values_count-1);
7664 }
7665#endif
7666
David Hendricks7d48ac52018-03-09 14:30:38 -08007667 } else {
7668 /* If nothing passed use the default Vref value for this rank */
7669 bdk_lmcx_modereg_params2_t lmc_modereg_params2;
7670 lmc_modereg_params2.u = BDK_CSR_READ(node, BDK_LMCX_MODEREG_PARAMS2(ddr_interface_num));
7671 final_vref_value = (lmc_modereg_params2.u >> (rankx * 10 + 3)) & 0x3f;
7672 final_vref_range = (lmc_modereg_params2.u >> (rankx * 10 + 9)) & 0x01;
David Hendricks2004b932018-03-09 13:58:27 -08007673
David Hendricks7d48ac52018-03-09 14:30:38 -08007674 ddr_print("N%d.LMC%d.R%d: Vref Using Default :"
7675 " %2d <----- %2d (0x%02x) -----> %2d, range%1d\n",
7676 node, ddr_interface_num, rankx,
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007677 final_vref_value, final_vref_value,
David Hendricks7d48ac52018-03-09 14:30:38 -08007678 final_vref_value, final_vref_value, final_vref_range+1);
7679 }
7680 }
David Hendricks2004b932018-03-09 13:58:27 -08007681
David Hendricks7d48ac52018-03-09 14:30:38 -08007682 // allow override
David Hendricks2004b932018-03-09 13:58:27 -08007683 if ((s = lookup_env_parameter("ddr%d_vref_value_%1d%1d",
7684 ddr_interface_num, !!(rankx&2), !!(rankx&1))) != NULL) {
7685 final_vref_value = strtoul(s, NULL, 0);
7686 }
7687
David Hendricks7d48ac52018-03-09 14:30:38 -08007688 set_vref(node, ddr_interface_num, rankx, final_vref_range, final_vref_value);
David Hendricks2004b932018-03-09 13:58:27 -08007689
David Hendricks7d48ac52018-03-09 14:30:38 -08007690 } /* if (vref_value < VREF_FINAL) */
David Hendricks2004b932018-03-09 13:58:27 -08007691 } /* if (ddr_type == DDR4_DRAM) */
7692
7693 lmc_wlevel_rank.u = lmc_wlevel_rank_hw_results.u; /* Restore the saved value */
7694
David Hendricks7d48ac52018-03-09 14:30:38 -08007695 for (byte = 0; byte < 9; ++byte)
7696 byte_test_status[byte] = WL_ESTIMATED;
David Hendricks2004b932018-03-09 13:58:27 -08007697
7698 if (wlevel_bitmask_errors == 0) {
7699
7700 /* Determine address of DRAM to test for pass 1 of software write leveling. */
7701 rank_addr = active_rank * (1ull << (pbank_lsb - bunk_enable + (interfaces/2)));
7702 // FIXME: these now put in by test_dram_byte()
7703 //rank_addr |= (ddr_interface_num<<7); /* Map address into proper interface */
7704 //rank_addr = bdk_numa_get_address(node, rank_addr);
David Hendricks7d48ac52018-03-09 14:30:38 -08007705 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: Active Rank %d Address: 0x%llx\n",
David Hendricks2004b932018-03-09 13:58:27 -08007706 node, ddr_interface_num, rankx, active_rank, rank_addr);
7707
David Hendricks7d48ac52018-03-09 14:30:38 -08007708 { // start parallel write-leveling block for delay high-order bits
7709 int errors = 0;
7710 int byte_delay[9];
7711 uint64_t bytemask;
7712 int bytes_todo;
David Hendricks2004b932018-03-09 13:58:27 -08007713
7714 if (ddr_interface_64b) {
7715 bytes_todo = (sw_wlevel_hw) ? ddr_interface_bytemask : 0xFF;
7716 bytemask = ~0ULL;
7717 } else { // 32-bit, must be using SW algo, only data bytes
7718 bytes_todo = 0x0f;
7719 bytemask = 0x00000000ffffffffULL;
7720 }
7721
David Hendricks7d48ac52018-03-09 14:30:38 -08007722 for (byte = 0; byte < 9; ++byte) {
7723 if (!(bytes_todo & (1 << byte))) {
7724 byte_delay[byte] = 0;
7725 } else {
7726 byte_delay[byte] = get_wlevel_rank_struct(&lmc_wlevel_rank, byte);
7727 }
7728 } /* for (byte = 0; byte < 9; ++byte) */
David Hendricks2004b932018-03-09 13:58:27 -08007729
7730#define WL_MIN_NO_ERRORS_COUNT 3 // FIXME? three passes without errors
David Hendricks7d48ac52018-03-09 14:30:38 -08007731 int no_errors_count = 0;
David Hendricks2004b932018-03-09 13:58:27 -08007732
7733 // Change verbosity if using measured vs computed VREF or DDR3
7734 // measured goes many times through SWL, computed and DDR3 only once
7735 // so we want the EXHAUSTED messages at NORM for computed and DDR3,
7736 // and at DEV2 for measured, just for completeness
7737 int vbl_local = (measured_vref_flag) ? VBL_DEV2 : VBL_NORM;
7738 uint64_t bad_bits[2];
7739#if ENABLE_SW_WLEVEL_UTILIZATION
7740 uint64_t sum_dram_dclk = 0, sum_dram_ops = 0;
7741 uint64_t start_dram_dclk, stop_dram_dclk;
7742 uint64_t start_dram_ops, stop_dram_ops;
7743#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08007744 do {
7745 // write the current set of WL delays
7746 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
7747 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08007748
David Hendricks7d48ac52018-03-09 14:30:38 -08007749 bdk_watchdog_poke();
David Hendricks2004b932018-03-09 13:58:27 -08007750
David Hendricks7d48ac52018-03-09 14:30:38 -08007751 // do the test
David Hendricks2004b932018-03-09 13:58:27 -08007752 if (sw_wlevel_hw) {
7753 errors = run_best_hw_patterns(node, ddr_interface_num, rank_addr,
7754 DBTRAIN_TEST, bad_bits);
7755 errors &= bytes_todo; // keep only the ones we are still doing
7756 } else {
7757#if ENABLE_SW_WLEVEL_UTILIZATION
7758 start_dram_dclk = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(ddr_interface_num));
7759 start_dram_ops = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(ddr_interface_num));
7760#endif
7761#if USE_ORIG_TEST_DRAM_BYTE
7762 errors = test_dram_byte(node, ddr_interface_num, rank_addr, bytemask, bad_bits);
7763#else
7764 errors = dram_tuning_mem_xor(node, ddr_interface_num, rank_addr, bytemask, bad_bits);
7765#endif
7766#if ENABLE_SW_WLEVEL_UTILIZATION
7767 stop_dram_dclk = BDK_CSR_READ(node, BDK_LMCX_DCLK_CNT(ddr_interface_num));
7768 stop_dram_ops = BDK_CSR_READ(node, BDK_LMCX_OPS_CNT(ddr_interface_num));
7769 sum_dram_dclk += stop_dram_dclk - start_dram_dclk;
7770 sum_dram_ops += stop_dram_ops - start_dram_ops;
7771#endif
7772 }
7773
David Hendricks7d48ac52018-03-09 14:30:38 -08007774 VB_PRT(VBL_DEV2, "N%d.LMC%d.R%d: S/W write-leveling TEST: returned 0x%x\n",
David Hendricks2004b932018-03-09 13:58:27 -08007775 node, ddr_interface_num, rankx, errors);
7776
David Hendricks7d48ac52018-03-09 14:30:38 -08007777 // remember, errors will not be returned for byte-lanes that have maxxed out...
David Hendricks2004b932018-03-09 13:58:27 -08007778 if (errors == 0) {
7779 no_errors_count++; // bump
7780 if (no_errors_count > 1) // bypass check/update completely
7781 continue; // to end of do-while
7782 } else
7783 no_errors_count = 0; // reset
7784
David Hendricks7d48ac52018-03-09 14:30:38 -08007785 // check errors by byte
7786 for (byte = 0; byte < 9; ++byte) {
7787 if (!(bytes_todo & (1 << byte)))
7788 continue;
David Hendricks2004b932018-03-09 13:58:27 -08007789
David Hendricks7d48ac52018-03-09 14:30:38 -08007790 delay = byte_delay[byte];
7791 if (errors & (1 << byte)) { // yes, an error in this byte lane
7792 debug_print(" byte %d delay %2d Errors\n", byte, delay);
7793 // since this byte had an error, we move to the next delay value, unless maxxed out
7794 delay += 8; // incr by 8 to do only delay high-order bits
7795 if (delay < 32) {
7796 update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
7797 debug_print(" byte %d delay %2d New\n", byte, delay);
7798 byte_delay[byte] = delay;
7799 } else { // reached max delay, maybe really done with this byte
David Hendricks2004b932018-03-09 13:58:27 -08007800#if SWL_TRY_HWL_ALT
David Hendricks7d48ac52018-03-09 14:30:38 -08007801 if (!measured_vref_flag && // consider an alt only for computed VREF and
David Hendricks2004b932018-03-09 13:58:27 -08007802 (hwl_alts[rankx].hwl_alt_mask & (1 << byte))) // if an alt exists...
7803 {
7804 int bad_delay = delay & 0x6; // just orig low-3 bits
David Hendricks7d48ac52018-03-09 14:30:38 -08007805 delay = hwl_alts[rankx].hwl_alt_delay[byte]; // yes, use it
7806 hwl_alts[rankx].hwl_alt_mask &= ~(1 << byte); // clear that flag
7807 update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
7808 byte_delay[byte] = delay;
7809 debug_print(" byte %d delay %2d ALTERNATE\n", byte, delay);
7810 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: SWL: Byte %d: %d FAIL, trying ALTERNATE %d\n",
David Hendricks2004b932018-03-09 13:58:27 -08007811 node, ddr_interface_num, rankx, byte, bad_delay, delay);
7812
David Hendricks7d48ac52018-03-09 14:30:38 -08007813 } else
David Hendricks2004b932018-03-09 13:58:27 -08007814#endif /* SWL_TRY_HWL_ALT */
7815 {
7816 unsigned bits_bad;
David Hendricks7d48ac52018-03-09 14:30:38 -08007817 if (byte < 8) {
David Hendricks2004b932018-03-09 13:58:27 -08007818 bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask
7819 bits_bad = (unsigned)((bad_bits[0] >> (8 * byte)) & 0xffUL);
7820 } else {
7821 bits_bad = (unsigned)(bad_bits[1] & 0xffUL);
7822 }
7823 bytes_todo &= ~(1 << byte); // remove from bytes to do
7824 byte_test_status[byte] = WL_ESTIMATED; // make sure this is set for this case
7825 debug_print(" byte %d delay %2d Exhausted\n", byte, delay);
David Hendricks7d48ac52018-03-09 14:30:38 -08007826 VB_PRT(vbl_local, "N%d.LMC%d.R%d: SWL: Byte %d (0x%02x): delay %d EXHAUSTED \n",
David Hendricks2004b932018-03-09 13:58:27 -08007827 node, ddr_interface_num, rankx, byte, bits_bad, delay);
7828 }
David Hendricks7d48ac52018-03-09 14:30:38 -08007829 }
7830 } else { // no error, stay with current delay, but keep testing it...
7831 debug_print(" byte %d delay %2d Passed\n", byte, delay);
7832 byte_test_status[byte] = WL_HARDWARE; // change status
7833 }
David Hendricks2004b932018-03-09 13:58:27 -08007834
David Hendricks7d48ac52018-03-09 14:30:38 -08007835 } /* for (byte = 0; byte < 9; ++byte) */
David Hendricks2004b932018-03-09 13:58:27 -08007836
David Hendricks7d48ac52018-03-09 14:30:38 -08007837 } while (no_errors_count < WL_MIN_NO_ERRORS_COUNT);
David Hendricks2004b932018-03-09 13:58:27 -08007838
7839#if ENABLE_SW_WLEVEL_UTILIZATION
7840 if (! sw_wlevel_hw) {
7841 uint64_t percent_x10;
7842 if (sum_dram_dclk == 0)
7843 sum_dram_dclk = 1;
7844 percent_x10 = sum_dram_ops * 1000 / sum_dram_dclk;
7845 ddr_print("N%d.LMC%d.R%d: ops %lu, cycles %lu, used %lu.%lu%%\n",
7846 node, ddr_interface_num, rankx, sum_dram_ops, sum_dram_dclk,
7847 percent_x10 / 10, percent_x10 % 10);
7848 }
7849#endif
David Hendricks7d48ac52018-03-09 14:30:38 -08007850 if (errors) {
7851 debug_print("End WLEV_64 while loop: vref_value %d(0x%x), errors 0x%02x\n",
7852 vref_value, vref_value, errors);
7853 }
7854 } // end parallel write-leveling block for delay high-order bits
David Hendricks2004b932018-03-09 13:58:27 -08007855
7856 if (sw_wlevel_hw) { // if we used HW-assist, we did the ECC byte when approp.
7857 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: HW-assist SWL - no ECC estimate!!!\n",
7858 node, ddr_interface_num, rankx);
7859 goto no_ecc_estimate;
7860 }
7861
7862 if ((ddr_interface_bytemask & 0xff) == 0xff) {
7863 if (use_ecc) {
7864 int save_byte8 = lmc_wlevel_rank.s.byte8; // save original HW delay
7865 byte_test_status[8] = WL_HARDWARE; /* say it is H/W delay value */
7866
7867 if ((save_byte8 != lmc_wlevel_rank.s.byte3) &&
7868 (save_byte8 != lmc_wlevel_rank.s.byte4))
David Hendricks7d48ac52018-03-09 14:30:38 -08007869 {
7870 // try to calculate a workable delay using SW bytes 3 and 4 and HW byte 8
David Hendricks2004b932018-03-09 13:58:27 -08007871 int test_byte8 = save_byte8;
7872 int test_byte8_error;
7873 int byte8_error = 0x1f;
7874 int adder;
David Hendricks7d48ac52018-03-09 14:30:38 -08007875 int avg_bytes = divide_nint(lmc_wlevel_rank.s.byte3+lmc_wlevel_rank.s.byte4, 2);
David Hendricks2004b932018-03-09 13:58:27 -08007876 for (adder = 0; adder<= 32; adder+=8) {
7877 test_byte8_error = _abs((adder+save_byte8) - avg_bytes);
7878 if (test_byte8_error < byte8_error) {
7879 byte8_error = test_byte8_error;
7880 test_byte8 = save_byte8 + adder;
7881 }
7882 }
7883
7884#if SW_WL_CHECK_PATCH
David Hendricks7d48ac52018-03-09 14:30:38 -08007885 // only do the check if we are not using measured VREF
7886 if (!measured_vref_flag) {
David Hendricks2004b932018-03-09 13:58:27 -08007887 test_byte8 &= ~1; /* Use only even settings, rounding down... */
7888
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01007889 // do validity check on the calculated ECC delay value
David Hendricks2004b932018-03-09 13:58:27 -08007890 // this depends on the DIMM type
7891 if (spd_rdimm) { // RDIMM
7892 if (spd_dimm_type != 5) { // but not mini-RDIMM
7893 // it can be > byte4, but should never be > byte3
7894 if (test_byte8 > lmc_wlevel_rank.s.byte3) {
7895 byte_test_status[8] = WL_ESTIMATED; /* say it is still estimated */
7896 }
7897 }
7898 } else { // UDIMM
7899 if ((test_byte8 < lmc_wlevel_rank.s.byte3) ||
7900 (test_byte8 > lmc_wlevel_rank.s.byte4))
7901 { // should never be outside the byte 3-4 range
7902 byte_test_status[8] = WL_ESTIMATED; /* say it is still estimated */
7903 }
7904 }
7905 /*
7906 * Report whenever the calculation appears bad.
7907 * This happens if some of the original values were off, or unexpected geometry
7908 * from DIMM type, or custom circuitry (NIC225E, I am looking at you!).
7909 * We will trust the calculated value, and depend on later testing to catch
7910 * any instances when that value is truly bad.
7911 */
7912 if (byte_test_status[8] == WL_ESTIMATED) { // ESTIMATED means there may be an issue
7913 ddr_print("N%d.LMC%d.R%d: SWL: (%cDIMM): calculated ECC delay unexpected (%d/%d/%d)\n",
7914 node, ddr_interface_num, rankx, (spd_rdimm?'R':'U'),
7915 lmc_wlevel_rank.s.byte4, test_byte8, lmc_wlevel_rank.s.byte3);
7916 byte_test_status[8] = WL_HARDWARE;
7917 }
7918 }
7919#endif /* SW_WL_CHECK_PATCH */
7920 lmc_wlevel_rank.s.byte8 = test_byte8 & ~1; /* Use only even settings */
7921 }
7922
7923 if (lmc_wlevel_rank.s.byte8 != save_byte8) {
7924 /* Change the status if s/w adjusted the delay */
7925 byte_test_status[8] = WL_SOFTWARE; /* Estimated delay */
7926 }
7927 } else {
David Hendricks7d48ac52018-03-09 14:30:38 -08007928 byte_test_status[8] = WL_HARDWARE; /* H/W delay value */
David Hendricks2004b932018-03-09 13:58:27 -08007929 lmc_wlevel_rank.s.byte8 = lmc_wlevel_rank.s.byte0; /* ECC is not used */
7930 }
7931 } else { /* if ((ddr_interface_bytemask & 0xff) == 0xff) */
7932 if (use_ecc) {
7933 /* Estimate the ECC byte delay */
7934 lmc_wlevel_rank.s.byte4 |= (lmc_wlevel_rank.s.byte3 & 0x38); // add hi-order to b4
7935 if ((lmc_wlevel_rank.s.byte4 & 0x06) < (lmc_wlevel_rank.s.byte3 & 0x06)) // orig b4 < orig b3
7936 lmc_wlevel_rank.s.byte4 += 8; // must be next clock
7937 } else {
7938 lmc_wlevel_rank.s.byte4 = lmc_wlevel_rank.s.byte0; /* ECC is not used */
7939 }
7940 /* Change the status if s/w adjusted the delay */
7941 byte_test_status[4] = WL_SOFTWARE; /* Estimated delay */
7942 } /* if ((ddr_interface_bytemask & 0xff) == 0xff) */
7943 } /* if (wlevel_bitmask_errors == 0) */
7944
7945 no_ecc_estimate:
7946
7947 bytes_failed = 0;
7948 for (byte = 0; byte < 9; ++byte) {
7949 /* Don't accumulate errors for untested bytes. */
7950 if (!(ddr_interface_bytemask & (1 << byte)))
7951 continue;
7952 bytes_failed += (byte_test_status[byte] == WL_ESTIMATED);
7953 }
7954
7955 /* Vref training loop is only used for DDR4 */
7956 if (ddr_type != DDR4_DRAM)
David Hendricks7d48ac52018-03-09 14:30:38 -08007957 break;
David Hendricks2004b932018-03-09 13:58:27 -08007958
7959 if (bytes_failed == 0) {
7960 if (vref_values_count == 0) {
7961 vref_values_start = vref_value;
7962 }
7963 ++vref_values_count;
7964 if (vref_values_count > best_vref_values_count) {
7965 best_vref_values_count = vref_values_count;
7966 best_vref_values_start = vref_values_start;
7967 debug_print("N%d.LMC%d.R%d: Vref Training (%2d) : 0x%02x <----- ???? -----> 0x%02x\n",
David Hendricks7d48ac52018-03-09 14:30:38 -08007968 node, ddr_interface_num,
David Hendricks2004b932018-03-09 13:58:27 -08007969 rankx, vref_value, best_vref_values_start,
7970 best_vref_values_start+best_vref_values_count-1);
7971 }
7972 } else {
7973 vref_values_count = 0;
David Hendricks7d48ac52018-03-09 14:30:38 -08007974 debug_print("N%d.LMC%d.R%d: Vref Training (%2d) : failed\n",
7975 node, ddr_interface_num,
7976 rankx, vref_value);
David Hendricks2004b932018-03-09 13:58:27 -08007977 }
7978 } /* for (vref_value=0; vref_value<VREF_LIMIT; ++vref_value) */
7979
David Hendricks7d48ac52018-03-09 14:30:38 -08007980 /* Determine address of DRAM to test for pass 2 and final test of software write leveling. */
David Hendricks2004b932018-03-09 13:58:27 -08007981 rank_addr = active_rank * (1ull << (pbank_lsb - bunk_enable + (interfaces/2)));
David Hendricks7d48ac52018-03-09 14:30:38 -08007982 rank_addr |= (ddr_interface_num<<7); /* Map address into proper interface */
7983 rank_addr = bdk_numa_get_address(node, rank_addr);
7984 debug_print("N%d.LMC%d.R%d: Active Rank %d Address: 0x%lx\n",
7985 node, ddr_interface_num, rankx, active_rank, rank_addr);
David Hendricks2004b932018-03-09 13:58:27 -08007986
David Hendricks7d48ac52018-03-09 14:30:38 -08007987 int errors;
David Hendricks2004b932018-03-09 13:58:27 -08007988
7989 if (bytes_failed) {
7990
7991#if !DISABLE_SW_WL_PASS_2
7992
David Hendricks7d48ac52018-03-09 14:30:38 -08007993 ddr_print("N%d.LMC%d.R%d: Starting SW Write-leveling pass 2\n",
7994 node, ddr_interface_num, rankx);
David Hendricks2004b932018-03-09 13:58:27 -08007995 sw_wl_rank_status = WL_SOFTWARE;
7996
7997 /* If previous s/w fixups failed then retry using s/w write-leveling. */
7998 if (wlevel_bitmask_errors == 0) {
David Hendricks7d48ac52018-03-09 14:30:38 -08007999 /* h/w succeeded but previous s/w fixups failed. So retry s/w. */
David Hendricks2004b932018-03-09 13:58:27 -08008000 debug_print("N%d.LMC%d.R%d: Retrying software Write-Leveling.\n",
David Hendricks7d48ac52018-03-09 14:30:38 -08008001 node, ddr_interface_num, rankx);
David Hendricks2004b932018-03-09 13:58:27 -08008002 }
8003
David Hendricks7d48ac52018-03-09 14:30:38 -08008004 { // start parallel write-leveling block for delay low-order bits
8005 int byte_delay[8];
8006 int byte_passed[8];
8007 uint64_t bytemask;
8008 uint64_t bitmask;
David Hendricks2004b932018-03-09 13:58:27 -08008009 int wl_offset;
David Hendricks7d48ac52018-03-09 14:30:38 -08008010 int bytes_todo;
David Hendricks2004b932018-03-09 13:58:27 -08008011
David Hendricks7d48ac52018-03-09 14:30:38 -08008012 for (byte = 0; byte < 8; ++byte) {
8013 byte_passed[byte] = 0;
8014 }
David Hendricks2004b932018-03-09 13:58:27 -08008015
David Hendricks7d48ac52018-03-09 14:30:38 -08008016 bytes_todo = ddr_interface_bytemask;
David Hendricks2004b932018-03-09 13:58:27 -08008017
8018 for (wl_offset = sw_wlevel_offset; wl_offset >= 0; --wl_offset) {
David Hendricks7d48ac52018-03-09 14:30:38 -08008019 debug_print("Starting wl_offset for-loop: %d\n", wl_offset);
David Hendricks2004b932018-03-09 13:58:27 -08008020
David Hendricks7d48ac52018-03-09 14:30:38 -08008021 bytemask = 0;
David Hendricks2004b932018-03-09 13:58:27 -08008022
David Hendricks7d48ac52018-03-09 14:30:38 -08008023 for (byte = 0; byte < 8; ++byte) {
8024 byte_delay[byte] = 0;
8025 if (!(bytes_todo & (1 << byte))) // this does not contain fully passed bytes
8026 continue;
David Hendricks2004b932018-03-09 13:58:27 -08008027
David Hendricks7d48ac52018-03-09 14:30:38 -08008028 byte_passed[byte] = 0; // reset across passes if not fully passed
8029 update_wlevel_rank_struct(&lmc_wlevel_rank, byte, 0); // all delays start at 0
8030 bitmask = ((!ddr_interface_64b) && (byte == 4)) ? 0x0f: 0xff;
8031 bytemask |= bitmask << (8*byte); // set the bytes bits in the bytemask
8032 } /* for (byte = 0; byte < 8; ++byte) */
David Hendricks2004b932018-03-09 13:58:27 -08008033
David Hendricks7d48ac52018-03-09 14:30:38 -08008034 while (bytemask != 0) { // start a pass if there is any byte lane to test
David Hendricks2004b932018-03-09 13:58:27 -08008035
David Hendricks7d48ac52018-03-09 14:30:38 -08008036 debug_print("Starting bytemask while-loop: 0x%lx\n", bytemask);
David Hendricks2004b932018-03-09 13:58:27 -08008037
David Hendricks7d48ac52018-03-09 14:30:38 -08008038 // write this set of WL delays
8039 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
8040 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08008041
David Hendricks7d48ac52018-03-09 14:30:38 -08008042 bdk_watchdog_poke();
David Hendricks2004b932018-03-09 13:58:27 -08008043
David Hendricks7d48ac52018-03-09 14:30:38 -08008044 // do the test
David Hendricks2004b932018-03-09 13:58:27 -08008045 if (sw_wlevel_hw)
8046 errors = run_best_hw_patterns(node, ddr_interface_num, rank_addr,
8047 DBTRAIN_TEST, NULL);
8048 else
8049 errors = test_dram_byte(node, ddr_interface_num, rank_addr, bytemask, NULL);
8050
David Hendricks7d48ac52018-03-09 14:30:38 -08008051 debug_print("SWL pass 2: test_dram_byte returned 0x%x\n", errors);
David Hendricks2004b932018-03-09 13:58:27 -08008052
David Hendricks7d48ac52018-03-09 14:30:38 -08008053 // check errors by byte
8054 for (byte = 0; byte < 8; ++byte) {
8055 if (!(bytes_todo & (1 << byte)))
8056 continue;
David Hendricks2004b932018-03-09 13:58:27 -08008057
David Hendricks7d48ac52018-03-09 14:30:38 -08008058 delay = byte_delay[byte];
8059 if (errors & (1 << byte)) { // yes, an error
8060 debug_print(" byte %d delay %2d Errors\n", byte, delay);
8061 byte_passed[byte] = 0;
8062 } else { // no error
8063 byte_passed[byte] += 1;
8064 if (byte_passed[byte] == (1 + wl_offset)) { /* Look for consecutive working settings */
8065 debug_print(" byte %d delay %2d FULLY Passed\n", byte, delay);
8066 if (wl_offset == 1) {
8067 byte_test_status[byte] = WL_SOFTWARE;
8068 } else if (wl_offset == 0) {
8069 byte_test_status[byte] = WL_SOFTWARE1;
8070 }
8071 bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
8072 bytes_todo &= ~(1 << byte); // remove completely from concern
8073 continue; // on to the next byte, bypass delay updating!!
8074 } else {
8075 debug_print(" byte %d delay %2d Passed\n", byte, delay);
8076 }
8077 }
8078 // error or no, here we move to the next delay value for this byte, unless done all delays
8079 // only a byte that has "fully passed" will bypass around this,
8080 delay += 2;
8081 if (delay < 32) {
8082 update_wlevel_rank_struct(&lmc_wlevel_rank, byte, delay);
8083 debug_print(" byte %d delay %2d New\n", byte, delay);
8084 byte_delay[byte] = delay;
8085 } else {
8086 // reached max delay, done with this byte
8087 debug_print(" byte %d delay %2d Exhausted\n", byte, delay);
8088 bytemask &= ~(0xffULL << (8*byte)); // test no longer, remove from byte mask this pass
8089 }
8090 } /* for (byte = 0; byte < 8; ++byte) */
8091 debug_print("End of for-loop: bytemask 0x%lx\n", bytemask);
David Hendricks2004b932018-03-09 13:58:27 -08008092
David Hendricks7d48ac52018-03-09 14:30:38 -08008093 } /* while (bytemask != 0) */
8094 } /* for (wl_offset = sw_wlevel_offset; wl_offset >= 0; --wl_offset) */
David Hendricks2004b932018-03-09 13:58:27 -08008095
David Hendricks7d48ac52018-03-09 14:30:38 -08008096 for (byte = 0; byte < 8; ++byte) {
8097 // any bytes left in bytes_todo did not pass
8098 if (bytes_todo & (1 << byte)) {
8099 /* Last resort. Use Rlevel settings to estimate
8100 Wlevel if software write-leveling fails */
8101 debug_print("Using RLEVEL as WLEVEL estimate for byte %d\n", byte);
8102 lmc_rlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_RLEVEL_RANKX(ddr_interface_num, rankx));
8103 rlevel_to_wlevel(&lmc_rlevel_rank, &lmc_wlevel_rank, byte);
8104 }
8105 } /* for (byte = 0; byte < 8; ++byte) */
David Hendricks2004b932018-03-09 13:58:27 -08008106
David Hendricks7d48ac52018-03-09 14:30:38 -08008107 sw_wl_failed = (bytes_todo != 0);
David Hendricks2004b932018-03-09 13:58:27 -08008108
David Hendricks7d48ac52018-03-09 14:30:38 -08008109 } // end parallel write-leveling block for delay low-order bits
David Hendricks2004b932018-03-09 13:58:27 -08008110
8111 if (use_ecc) {
8112 /* ECC byte has to be estimated. Take the average of the two surrounding bytes. */
8113 int test_byte8 = divide_nint(lmc_wlevel_rank.s.byte3
8114 + lmc_wlevel_rank.s.byte4
8115 + 2 /* round-up*/ , 2);
8116 lmc_wlevel_rank.s.byte8 = test_byte8 & ~1; /* Use only even settings */
8117 byte_test_status[8] = WL_ESTIMATED; /* Estimated delay */
8118 } else {
8119 byte_test_status[8] = WL_HARDWARE; /* H/W delay value */
8120 lmc_wlevel_rank.s.byte8 = lmc_wlevel_rank.s.byte0; /* ECC is not used */
8121 }
8122
8123 /* Set delays for unused bytes to match byte 0. */
8124 for (byte=0; byte<8; ++byte) {
8125 if ((ddr_interface_bytemask & (1 << byte)))
8126 continue;
8127 update_wlevel_rank_struct(&lmc_wlevel_rank, byte,
David Hendricks7d48ac52018-03-09 14:30:38 -08008128 lmc_wlevel_rank.s.byte0);
David Hendricks2004b932018-03-09 13:58:27 -08008129 byte_test_status[byte] = WL_SOFTWARE;
8130 }
8131#else /* !DISABLE_SW_WL_PASS_2 */
David Hendricks7d48ac52018-03-09 14:30:38 -08008132 // FIXME? the big hammer, did not even try SW WL pass2, assume only chip reset will help
8133 ddr_print("N%d.LMC%d.R%d: S/W write-leveling pass 1 failed\n",
8134 node, ddr_interface_num, rankx);
8135 sw_wl_failed = 1;
David Hendricks2004b932018-03-09 13:58:27 -08008136#endif /* !DISABLE_SW_WL_PASS_2 */
8137
8138 } else { /* if (bytes_failed) */
8139
David Hendricks7d48ac52018-03-09 14:30:38 -08008140 // SW WL pass 1 was OK, write the settings
8141 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
8142 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks2004b932018-03-09 13:58:27 -08008143
8144#if SW_WL_CHECK_PATCH
David Hendricks7d48ac52018-03-09 14:30:38 -08008145 // do validity check on the delay values by running the test 1 more time...
8146 // FIXME: we really need to check the ECC byte setting here as well,
8147 // so we need to enable ECC for this test!!!
8148 // if there are any errors, claim SW WL failure
8149 {
8150 uint64_t datamask = (ddr_interface_64b) ? 0xffffffffffffffffULL : 0x00000000ffffffffULL;
David Hendricks2004b932018-03-09 13:58:27 -08008151
8152 // do the test
8153 if (sw_wlevel_hw) {
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008154 errors = run_best_hw_patterns(node, ddr_interface_num, rank_addr,
David Hendricks2004b932018-03-09 13:58:27 -08008155 DBTRAIN_TEST, NULL) & 0x0ff;
8156 } else {
8157#if USE_ORIG_TEST_DRAM_BYTE
8158 errors = test_dram_byte(node, ddr_interface_num, rank_addr, datamask, NULL);
8159#else
8160 errors = dram_tuning_mem_xor(node, ddr_interface_num, rank_addr, datamask, NULL);
8161#endif
8162 }
8163
David Hendricks7d48ac52018-03-09 14:30:38 -08008164 if (errors) {
8165 ddr_print("N%d.LMC%d.R%d: Wlevel Rank Final Test errors 0x%x\n",
8166 node, ddr_interface_num, rankx, errors);
8167 sw_wl_failed = 1;
8168 }
8169 }
David Hendricks2004b932018-03-09 13:58:27 -08008170#endif /* SW_WL_CHECK_PATCH */
8171
David Hendricks7d48ac52018-03-09 14:30:38 -08008172 } /* if (bytes_failed) */
David Hendricks2004b932018-03-09 13:58:27 -08008173
David Hendricks7d48ac52018-03-09 14:30:38 -08008174 // FIXME? dump the WL settings, so we get more of a clue as to what happened where
8175 ddr_print("N%d.LMC%d.R%d: Wlevel Rank %#4x, 0x%016llX : %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %2d%3s %s\n",
David Hendricks2004b932018-03-09 13:58:27 -08008176 node, ddr_interface_num, rankx,
8177 lmc_wlevel_rank.s.status,
8178 lmc_wlevel_rank.u,
8179 lmc_wlevel_rank.s.byte8, wl_status_strings[byte_test_status[8]],
8180 lmc_wlevel_rank.s.byte7, wl_status_strings[byte_test_status[7]],
8181 lmc_wlevel_rank.s.byte6, wl_status_strings[byte_test_status[6]],
8182 lmc_wlevel_rank.s.byte5, wl_status_strings[byte_test_status[5]],
8183 lmc_wlevel_rank.s.byte4, wl_status_strings[byte_test_status[4]],
8184 lmc_wlevel_rank.s.byte3, wl_status_strings[byte_test_status[3]],
8185 lmc_wlevel_rank.s.byte2, wl_status_strings[byte_test_status[2]],
8186 lmc_wlevel_rank.s.byte1, wl_status_strings[byte_test_status[1]],
8187 lmc_wlevel_rank.s.byte0, wl_status_strings[byte_test_status[0]],
8188 (sw_wl_rank_status == WL_HARDWARE) ? "" : "(s)"
8189 );
8190
David Hendricks7d48ac52018-03-09 14:30:38 -08008191 // finally, check for fatal conditions: either chip reset right here, or return error flag
David Hendricks2004b932018-03-09 13:58:27 -08008192 if (((ddr_type == DDR4_DRAM) && (best_vref_values_count == 0)) || sw_wl_failed) {
8193 if (!ddr_disable_chip_reset) { // do chip RESET
8194 error_print("INFO: Short memory test indicates a retry is needed on N%d.LMC%d.R%d. Resetting node...\n",
8195 node, ddr_interface_num, rankx);
8196 bdk_wait_usec(500000);
8197 bdk_reset_chip(node);
8198 } else { // return error flag so LMC init can be retried...
8199 ddr_print("INFO: Short memory test indicates a retry is needed on N%d.LMC%d.R%d. Restarting LMC init...\n",
8200 node, ddr_interface_num, rankx);
8201 return 0; // 0 indicates restart possible...
8202 }
8203 }
8204
8205 active_rank++;
8206 } /* for (rankx = 0; rankx < dimm_count * 4; rankx++) */
8207
David Hendricks7d48ac52018-03-09 14:30:38 -08008208 // Finalize the write-leveling settings
David Hendricks2004b932018-03-09 13:58:27 -08008209 for (rankx = 0; rankx < dimm_count * 4;rankx++) {
8210 uint64_t value;
8211 int parameter_set = 0;
8212 if (!(rank_mask & (1 << rankx)))
8213 continue;
8214
8215 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
8216
David Hendricks2004b932018-03-09 13:58:27 -08008217 for (i=0; i<9; ++i) {
8218 if ((s = lookup_env_parameter("ddr%d_wlevel_rank%d_byte%d", ddr_interface_num, rankx, i)) != NULL) {
8219 parameter_set |= 1;
8220 value = strtoul(s, NULL, 0);
8221
8222 update_wlevel_rank_struct(&lmc_wlevel_rank, i, value);
8223 }
8224 }
8225
8226 if ((s = lookup_env_parameter_ull("ddr%d_wlevel_rank%d", ddr_interface_num, rankx)) != NULL) {
8227 parameter_set |= 1;
8228 value = strtoull(s, NULL, 0);
8229 lmc_wlevel_rank.u = value;
8230 }
8231
8232 if (parameter_set) {
8233 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx), lmc_wlevel_rank.u);
8234 lmc_wlevel_rank.u = BDK_CSR_READ(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, rankx));
David Hendricks7d48ac52018-03-09 14:30:38 -08008235 display_WL(node, ddr_interface_num, lmc_wlevel_rank, rankx);
David Hendricks2004b932018-03-09 13:58:27 -08008236 }
8237#if WLEXTRAS_PATCH
David Hendricks7d48ac52018-03-09 14:30:38 -08008238 if ((rank_mask & 0x0F) != 0x0F) { // if there are unused entries to be filled
8239 if (rankx < 3) {
8240 debug_print("N%d.LMC%d.R%d: checking for WLEVEL_RANK unused entries.\n",
8241 node, ddr_interface_num, rankx);
8242 if (rankx == 0) { // if rank 0, write ranks 1 and 2 here if empty
8243 if (!(rank_mask & (1<<1))) { // check that rank 1 is empty
8244 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 1), lmc_wlevel_rank.u);
8245 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
8246 node, ddr_interface_num, rankx, 1);
8247 }
8248 if (!(rank_mask & (1<<2))) { // check that rank 2 is empty
8249 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
8250 node, ddr_interface_num, rankx, 2);
8251 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 2), lmc_wlevel_rank.u);
8252 }
8253 }
8254 // if rank 0, 1 or 2, write rank 3 here if empty
8255 if (!(rank_mask & (1<<3))) { // check that rank 3 is empty
8256 VB_PRT(VBL_DEV, "N%d.LMC%d.R%d: writing WLEVEL_RANK unused entry R%d.\n",
8257 node, ddr_interface_num, rankx, 3);
8258 DRAM_CSR_WRITE(node, BDK_LMCX_WLEVEL_RANKX(ddr_interface_num, 3), lmc_wlevel_rank.u);
8259 }
8260 }
8261 }
David Hendricks2004b932018-03-09 13:58:27 -08008262#endif /* WLEXTRAS_PATCH */
8263
8264 } /* for (rankx = 0; rankx < dimm_count * 4;rankx++) */
8265
8266 /* Restore the ECC configuration */
8267 if (!sw_wlevel_hw_default) {
8268 lmc_config.s.ecc_ena = use_ecc;
8269 DRAM_CSR_WRITE(node, BDK_LMCX_CONFIG(ddr_interface_num), lmc_config.u);
8270 }
8271
8272#if USE_L2_WAYS_LIMIT
8273 /* Restore the l2 set configuration */
David Hendricks7d48ac52018-03-09 14:30:38 -08008274 if ((s = lookup_env_parameter("limit_l2_ways")) != NULL) {
David Hendricks2004b932018-03-09 13:58:27 -08008275 int ways = strtoul(s, NULL, 10);
8276 limit_l2_ways(node, ways, 1);
8277 } else {
8278 limit_l2_ways(node, bdk_l2c_get_num_assoc(node), 0);
8279 }
8280#endif
8281
8282 } // End Software Write-Leveling block
8283
8284#if ENABLE_DISPLAY_MPR_PAGE
8285 if (ddr_type == DDR4_DRAM) {
8286 Display_MPR_Page(node, rank_mask, ddr_interface_num, dimm_count, 2);
8287 Display_MPR_Page(node, rank_mask, ddr_interface_num, dimm_count, 0);
8288 }
8289#endif
8290
David Hendricks7d48ac52018-03-09 14:30:38 -08008291#ifdef CAVIUM_ONLY
David Hendricks2004b932018-03-09 13:58:27 -08008292 {
David Hendricks7d48ac52018-03-09 14:30:38 -08008293 int _i;
David Hendricks2004b932018-03-09 13:58:27 -08008294 int setting[9];
8295 bdk_lmcx_dll_ctl3_t ddr_dll_ctl3;
8296 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
8297
David Hendricks7d48ac52018-03-09 14:30:38 -08008298 for (_i=0; _i<9; ++_i) {
8299 SET_DDR_DLL_CTL3(dll90_byte_sel, ENCODE_DLL90_BYTE_SEL(_i));
8300 DRAM_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08008301 BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
8302 ddr_dll_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL3(ddr_interface_num));
David Hendricks7d48ac52018-03-09 14:30:38 -08008303 setting[_i] = GET_DDR_DLL_CTL3(dll90_setting);
8304 debug_print("%d. LMC%d_DLL_CTL3[%d] = %016lx %d\n", _i, ddr_interface_num,
8305 GET_DDR_DLL_CTL3(dll90_byte_sel), ddr_dll_ctl3.u, setting[_i]);
David Hendricks2004b932018-03-09 13:58:27 -08008306 }
8307
8308 VB_PRT(VBL_DEV, "N%d.LMC%d: %-36s : %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
8309 node, ddr_interface_num, "DLL90 Setting 8:0",
8310 setting[8], setting[7], setting[6], setting[5], setting[4],
8311 setting[3], setting[2], setting[1], setting[0]);
8312
David Hendricks7d48ac52018-03-09 14:30:38 -08008313 //BDK_CSR_WRITE(node, BDK_LMCX_DLL_CTL3(ddr_interface_num), save_ddr_dll_ctl3.u);
David Hendricks2004b932018-03-09 13:58:27 -08008314 }
8315#endif /* CAVIUM_ONLY */
8316
8317 // any custom DLL read or write offsets, install them
8318 // FIXME: no need to do these if we are going to auto-tune... ???
8319
8320 process_custom_dll_offsets(node, ddr_interface_num, "ddr_dll_write_offset",
David Hendricks7d48ac52018-03-09 14:30:38 -08008321 custom_lmc_config->dll_write_offset, "ddr%d_dll_write_offset_byte%d", 1);
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008322 process_custom_dll_offsets(node, ddr_interface_num, "ddr_dll_read_offset",
David Hendricks7d48ac52018-03-09 14:30:38 -08008323 custom_lmc_config->dll_read_offset, "ddr%d_dll_read_offset_byte%d", 2);
David Hendricks2004b932018-03-09 13:58:27 -08008324
8325 // we want to train write bit-deskew here...
8326 if (! disable_deskew_training) {
8327 if (enable_write_deskew) {
8328 ddr_print("N%d.LMC%d: WRITE BIT-DESKEW feature training begins.\n",
8329 node, ddr_interface_num);
8330 Perform_Write_Deskew_Training(node, ddr_interface_num);
8331 } /* if (enable_write_deskew) */
8332 } /* if (! disable_deskew_training) */
8333
8334 /*
8335 * 6.9.14 Final LMC Initialization
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008336 *
David Hendricks2004b932018-03-09 13:58:27 -08008337 * Early LMC initialization, LMC write-leveling, and LMC read-leveling
8338 * must be completed prior to starting this final LMC initialization.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008339 *
David Hendricks2004b932018-03-09 13:58:27 -08008340 * LMC hardware updates the LMC(0)_SLOT_CTL0, LMC(0)_SLOT_CTL1,
8341 * LMC(0)_SLOT_CTL2 CSRs with minimum values based on the selected
8342 * readleveling and write-leveling settings. Software should not write
8343 * the final LMC(0)_SLOT_CTL0, LMC(0)_SLOT_CTL1, and LMC(0)_SLOT_CTL2
8344 * values until after the final read-leveling and write-leveling settings
8345 * are written.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008346 *
David Hendricks2004b932018-03-09 13:58:27 -08008347 * Software must ensure the LMC(0)_SLOT_CTL0, LMC(0)_SLOT_CTL1, and
8348 * LMC(0)_SLOT_CTL2 CSR values are appropriate for this step. These CSRs
8349 * select the minimum gaps between read operations and write operations
8350 * of various types.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008351 *
David Hendricks2004b932018-03-09 13:58:27 -08008352 * Software must not reduce the values in these CSR fields below the
8353 * values previously selected by the LMC hardware (during write-leveling
8354 * and read-leveling steps above).
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008355 *
David Hendricks2004b932018-03-09 13:58:27 -08008356 * All sections in this chapter may be used to derive proper settings for
8357 * these registers.
Peter Lemenkov7bbe3bb2018-12-07 11:23:21 +01008358 *
David Hendricks2004b932018-03-09 13:58:27 -08008359 * For minimal read latency, L2C_CTL[EF_ENA,EF_CNT] should be programmed
8360 * properly. This should be done prior to the first read.
8361 */
8362
8363#if ENABLE_SLOT_CTL_ACCESS
8364 {
David Hendricks7d48ac52018-03-09 14:30:38 -08008365 bdk_lmcx_slot_ctl0_t lmc_slot_ctl0;
8366 bdk_lmcx_slot_ctl1_t lmc_slot_ctl1;
8367 bdk_lmcx_slot_ctl2_t lmc_slot_ctl2;
8368 bdk_lmcx_slot_ctl3_t lmc_slot_ctl3;
David Hendricks2004b932018-03-09 13:58:27 -08008369
8370 lmc_slot_ctl0.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL0(ddr_interface_num));
8371 lmc_slot_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num));
8372 lmc_slot_ctl2.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL2(ddr_interface_num));
8373 lmc_slot_ctl3.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL3(ddr_interface_num));
8374
8375 ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL0", lmc_slot_ctl0.u);
8376 ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
8377 ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL2", lmc_slot_ctl2.u);
8378 ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL3", lmc_slot_ctl3.u);
8379
David Hendricks7d48ac52018-03-09 14:30:38 -08008380 // for now, look only for SLOT_CTL1 envvar for override of contents
8381 if ((s = lookup_env_parameter("ddr%d_slot_ctl1", ddr_interface_num)) != NULL) {
8382 int slot_ctl1_incr = strtoul(s, NULL, 0);
8383 // validate the value
8384 if ((slot_ctl1_incr < 0) || (slot_ctl1_incr > 3)) { // allow 0 for printing only
8385 error_print("ddr%d_slot_ctl1 illegal value (%d); must be 0-3\n",
8386 ddr_interface_num, slot_ctl1_incr);
8387 } else {
David Hendricks2004b932018-03-09 13:58:27 -08008388
8389#define INCR(csr, chip, field, incr) \
David Hendricks7d48ac52018-03-09 14:30:38 -08008390 csr.chip.field = (csr.chip.field < (64 - incr)) ? (csr.chip.field + incr) : 63
David Hendricks2004b932018-03-09 13:58:27 -08008391
David Hendricks7d48ac52018-03-09 14:30:38 -08008392 // only print original when we are changing it!
8393 if (slot_ctl1_incr)
8394 ddr_print("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
David Hendricks2004b932018-03-09 13:58:27 -08008395
David Hendricks7d48ac52018-03-09 14:30:38 -08008396 // modify all the SLOT_CTL1 fields by the increment, for now...
8397 // but make sure the value will not overflow!!!
8398 INCR(lmc_slot_ctl1, s, r2r_xrank_init, slot_ctl1_incr);
8399 INCR(lmc_slot_ctl1, s, r2w_xrank_init, slot_ctl1_incr);
8400 INCR(lmc_slot_ctl1, s, w2r_xrank_init, slot_ctl1_incr);
8401 INCR(lmc_slot_ctl1, s, w2w_xrank_init, slot_ctl1_incr);
8402 DRAM_CSR_WRITE(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num), lmc_slot_ctl1.u);
8403 lmc_slot_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_SLOT_CTL1(ddr_interface_num));
David Hendricks2004b932018-03-09 13:58:27 -08008404
David Hendricks7d48ac52018-03-09 14:30:38 -08008405 // always print when we are changing it!
8406 printf("%-45s : 0x%016lx\n", "LMC_SLOT_CTL1", lmc_slot_ctl1.u);
8407 }
8408 }
David Hendricks2004b932018-03-09 13:58:27 -08008409 }
8410#endif /* ENABLE_SLOT_CTL_ACCESS */
8411 {
8412 /* Clear any residual ECC errors */
8413 int num_tads = 1;
8414 int tad;
8415
8416 DRAM_CSR_WRITE(node, BDK_LMCX_INT(ddr_interface_num), -1ULL);
8417 BDK_CSR_READ(node, BDK_LMCX_INT(ddr_interface_num));
8418
8419 for (tad=0; tad<num_tads; tad++)
8420 DRAM_CSR_WRITE(node, BDK_L2C_TADX_INT_W1C(tad), BDK_CSR_READ(node, BDK_L2C_TADX_INT_W1C(tad)));
8421
David Hendricks7d48ac52018-03-09 14:30:38 -08008422 ddr_print("%-45s : 0x%08llx\n", "LMC_INT",
David Hendricks2004b932018-03-09 13:58:27 -08008423 BDK_CSR_READ(node, BDK_LMCX_INT(ddr_interface_num)));
8424
David Hendricks2004b932018-03-09 13:58:27 -08008425 }
8426
8427 // Now we can enable scrambling if desired...
8428 {
8429 bdk_lmcx_control_t lmc_control;
8430 bdk_lmcx_scramble_cfg0_t lmc_scramble_cfg0;
8431 bdk_lmcx_scramble_cfg1_t lmc_scramble_cfg1;
8432 bdk_lmcx_scramble_cfg2_t lmc_scramble_cfg2;
8433 bdk_lmcx_ns_ctl_t lmc_ns_ctl;
8434
8435 lmc_control.u = BDK_CSR_READ(node, BDK_LMCX_CONTROL(ddr_interface_num));
8436 lmc_scramble_cfg0.u = BDK_CSR_READ(node, BDK_LMCX_SCRAMBLE_CFG0(ddr_interface_num));
8437 lmc_scramble_cfg1.u = BDK_CSR_READ(node, BDK_LMCX_SCRAMBLE_CFG1(ddr_interface_num));
8438 lmc_scramble_cfg2.u = BDK_CSR_READ(node, BDK_LMCX_SCRAMBLE_CFG2(ddr_interface_num));
8439 lmc_ns_ctl.u = BDK_CSR_READ(node, BDK_LMCX_NS_CTL(ddr_interface_num));
8440
8441 /* Read the scramble setting from the config and see if we
8442 need scrambling */
8443 int use_scramble = bdk_config_get_int(BDK_CONFIG_DRAM_SCRAMBLE);
8444 if (use_scramble == 2)
8445 {
8446 if (bdk_trust_get_level() >= BDK_TRUST_LEVEL_SIGNED)
8447 use_scramble = 1;
8448 else
8449 use_scramble = 0;
8450 }
8451
8452 /* Generate random values if scrambling is needed */
8453 if (use_scramble)
8454 {
8455 lmc_scramble_cfg0.u = bdk_rng_get_random64();
8456 lmc_scramble_cfg1.u = bdk_rng_get_random64();
8457 lmc_scramble_cfg2.u = bdk_rng_get_random64();
8458 lmc_ns_ctl.s.ns_scramble_dis = 0;
8459 lmc_ns_ctl.s.adr_offset = 0;
8460 lmc_control.s.scramble_ena = 1;
8461 }
8462
8463 if ((s = lookup_env_parameter_ull("ddr_scramble_cfg0")) != NULL) {
8464 lmc_scramble_cfg0.u = strtoull(s, NULL, 0);
8465 lmc_control.s.scramble_ena = 1;
8466 }
David Hendricks7d48ac52018-03-09 14:30:38 -08008467 ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG0", lmc_scramble_cfg0.u);
David Hendricks2004b932018-03-09 13:58:27 -08008468
8469 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG0(ddr_interface_num), lmc_scramble_cfg0.u);
8470
8471 if ((s = lookup_env_parameter_ull("ddr_scramble_cfg1")) != NULL) {
8472 lmc_scramble_cfg1.u = strtoull(s, NULL, 0);
8473 lmc_control.s.scramble_ena = 1;
8474 }
David Hendricks7d48ac52018-03-09 14:30:38 -08008475 ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG1", lmc_scramble_cfg1.u);
David Hendricks2004b932018-03-09 13:58:27 -08008476 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG1(ddr_interface_num), lmc_scramble_cfg1.u);
8477
8478 if ((s = lookup_env_parameter_ull("ddr_scramble_cfg2")) != NULL) {
8479 lmc_scramble_cfg2.u = strtoull(s, NULL, 0);
8480 lmc_control.s.scramble_ena = 1;
8481 }
David Hendricks7d48ac52018-03-09 14:30:38 -08008482 ddr_print("%-45s : 0x%016llx\n", "LMC_SCRAMBLE_CFG2", lmc_scramble_cfg2.u);
David Hendricks2004b932018-03-09 13:58:27 -08008483 DRAM_CSR_WRITE(node, BDK_LMCX_SCRAMBLE_CFG2(ddr_interface_num), lmc_scramble_cfg2.u);
8484
8485 if ((s = lookup_env_parameter_ull("ddr_ns_ctl")) != NULL) {
8486 lmc_ns_ctl.u = strtoull(s, NULL, 0);
8487 }
David Hendricks7d48ac52018-03-09 14:30:38 -08008488 ddr_print("%-45s : 0x%016llx\n", "LMC_NS_CTL", lmc_ns_ctl.u);
David Hendricks2004b932018-03-09 13:58:27 -08008489 DRAM_CSR_WRITE(node, BDK_LMCX_NS_CTL(ddr_interface_num), lmc_ns_ctl.u);
8490
8491 DRAM_CSR_WRITE(node, BDK_LMCX_CONTROL(ddr_interface_num), lmc_control.u);
8492
8493 }
8494
8495 return(mem_size_mbytes);
8496}