]>
Commit | Line | Data |
---|---|---|
58e5e9af | 1 | /* |
34e026f9 | 2 | * Copyright 2008-2014 Freescale Semiconductor, Inc. |
58e5e9af | 3 | * |
5b8031cc | 4 | * SPDX-License-Identifier: GPL-2.0 |
58e5e9af KG |
5 | */ |
6 | ||
7 | #include <common.h> | |
5614e71b | 8 | #include <fsl_ddr_sdram.h> |
58e5e9af | 9 | |
5614e71b | 10 | #include <fsl_ddr.h> |
58e5e9af | 11 | |
34e026f9 | 12 | #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) |
2ed2e912 | 13 | static unsigned int |
03e664d8 YS |
14 | compute_cas_latency(const unsigned int ctrl_num, |
15 | const dimm_params_t *dimm_params, | |
34e026f9 YS |
16 | common_timing_params_t *outpdimm, |
17 | unsigned int number_of_dimms) | |
c360ceac DL |
18 | { |
19 | unsigned int i; | |
c360ceac DL |
20 | unsigned int common_caslat; |
21 | unsigned int caslat_actual; | |
22 | unsigned int retry = 16; | |
6b95be22 | 23 | unsigned int tmp = ~0; |
03e664d8 | 24 | const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num); |
34e026f9 YS |
25 | #ifdef CONFIG_SYS_FSL_DDR3 |
26 | const unsigned int taamax = 20000; | |
27 | #else | |
28 | const unsigned int taamax = 18000; | |
29 | #endif | |
c360ceac DL |
30 | |
31 | /* compute the common CAS latency supported between slots */ | |
6b95be22 | 32 | for (i = 0; i < number_of_dimms; i++) { |
7e4db27f | 33 | if (dimm_params[i].n_ranks) |
0dd38a35 | 34 | tmp &= dimm_params[i].caslat_x; |
7e4db27f | 35 | } |
c360ceac DL |
36 | common_caslat = tmp; |
37 | ||
c360ceac | 38 | /* validate if the memory clk is in the range of dimms */ |
34e026f9 | 39 | if (mclk_ps < outpdimm->tckmin_x_ps) { |
d49f8e04 YS |
40 | printf("DDR clock (MCLK cycle %u ps) is faster than " |
41 | "the slowest DIMM(s) (tCKmin %u ps) can support.\n", | |
34e026f9 YS |
42 | mclk_ps, outpdimm->tckmin_x_ps); |
43 | } | |
44 | #ifdef CONFIG_SYS_FSL_DDR4 | |
45 | if (mclk_ps > outpdimm->tckmax_ps) { | |
46 | printf("DDR clock (MCLK cycle %u ps) is slower than DIMM(s) (tCKmax %u ps) can support.\n", | |
47 | mclk_ps, outpdimm->tckmax_ps); | |
c360ceac | 48 | } |
34e026f9 | 49 | #endif |
c360ceac | 50 | /* determine the acutal cas latency */ |
34e026f9 | 51 | caslat_actual = (outpdimm->taamin_ps + mclk_ps - 1) / mclk_ps; |
c360ceac DL |
52 | /* check if the dimms support the CAS latency */ |
53 | while (!(common_caslat & (1 << caslat_actual)) && retry > 0) { | |
54 | caslat_actual++; | |
55 | retry--; | |
56 | } | |
57 | /* once the caculation of caslat_actual is completed | |
58 | * we must verify that this CAS latency value does not | |
34e026f9 YS |
59 | * exceed tAAmax, which is 20 ns for all DDR3 speed grades, |
60 | * 18ns for all DDR4 speed grades. | |
c360ceac | 61 | */ |
34e026f9 | 62 | if (caslat_actual * mclk_ps > taamax) { |
c360ceac DL |
63 | printf("The choosen cas latency %d is too large\n", |
64 | caslat_actual); | |
c360ceac | 65 | } |
34e026f9 YS |
66 | outpdimm->lowest_common_spd_caslat = caslat_actual; |
67 | debug("lowest_common_spd_caslat is 0x%x\n", caslat_actual); | |
68 | ||
69 | return 0; | |
70 | } | |
71 | #else /* for DDR1 and DDR2 */ | |
72 | static unsigned int | |
03e664d8 YS |
73 | compute_cas_latency(const unsigned int ctrl_num, |
74 | const dimm_params_t *dimm_params, | |
34e026f9 YS |
75 | common_timing_params_t *outpdimm, |
76 | unsigned int number_of_dimms) | |
77 | { | |
78 | int i; | |
03e664d8 | 79 | const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num); |
34e026f9 YS |
80 | unsigned int lowest_good_caslat; |
81 | unsigned int not_ok; | |
82 | unsigned int temp1, temp2; | |
83 | ||
84 | debug("using mclk_ps = %u\n", mclk_ps); | |
85 | if (mclk_ps > outpdimm->tckmax_ps) { | |
86 | printf("Warning: DDR clock (%u ps) is slower than DIMM(s) (tCKmax %u ps)\n", | |
87 | mclk_ps, outpdimm->tckmax_ps); | |
88 | } | |
89 | ||
90 | /* | |
91 | * Compute a CAS latency suitable for all DIMMs | |
92 | * | |
93 | * Strategy for SPD-defined latencies: compute only | |
94 | * CAS latency defined by all DIMMs. | |
95 | */ | |
96 | ||
97 | /* | |
98 | * Step 1: find CAS latency common to all DIMMs using bitwise | |
99 | * operation. | |
100 | */ | |
101 | temp1 = 0xFF; | |
102 | for (i = 0; i < number_of_dimms; i++) { | |
103 | if (dimm_params[i].n_ranks) { | |
104 | temp2 = 0; | |
105 | temp2 |= 1 << dimm_params[i].caslat_x; | |
106 | temp2 |= 1 << dimm_params[i].caslat_x_minus_1; | |
107 | temp2 |= 1 << dimm_params[i].caslat_x_minus_2; | |
108 | /* | |
109 | * If there was no entry for X-2 (X-1) in | |
110 | * the SPD, then caslat_x_minus_2 | |
111 | * (caslat_x_minus_1) contains either 255 or | |
112 | * 0xFFFFFFFF because that's what the glorious | |
113 | * __ilog2 function returns for an input of 0. | |
114 | * On 32-bit PowerPC, left shift counts with bit | |
115 | * 26 set (that the value of 255 or 0xFFFFFFFF | |
116 | * will have), cause the destination register to | |
117 | * be 0. That is why this works. | |
118 | */ | |
119 | temp1 &= temp2; | |
120 | } | |
121 | } | |
122 | ||
123 | /* | |
124 | * Step 2: check each common CAS latency against tCK of each | |
125 | * DIMM's SPD. | |
126 | */ | |
127 | lowest_good_caslat = 0; | |
128 | temp2 = 0; | |
129 | while (temp1) { | |
130 | not_ok = 0; | |
131 | temp2 = __ilog2(temp1); | |
132 | debug("checking common caslat = %u\n", temp2); | |
133 | ||
134 | /* Check if this CAS latency will work on all DIMMs at tCK. */ | |
135 | for (i = 0; i < number_of_dimms; i++) { | |
136 | if (!dimm_params[i].n_ranks) | |
137 | continue; | |
138 | ||
139 | if (dimm_params[i].caslat_x == temp2) { | |
140 | if (mclk_ps >= dimm_params[i].tckmin_x_ps) { | |
141 | debug("CL = %u ok on DIMM %u at tCK=%u ps with tCKmin_X_ps of %u\n", | |
142 | temp2, i, mclk_ps, | |
143 | dimm_params[i].tckmin_x_ps); | |
144 | continue; | |
145 | } else { | |
146 | not_ok++; | |
147 | } | |
148 | } | |
149 | ||
150 | if (dimm_params[i].caslat_x_minus_1 == temp2) { | |
151 | unsigned int tckmin_x_minus_1_ps | |
152 | = dimm_params[i].tckmin_x_minus_1_ps; | |
153 | if (mclk_ps >= tckmin_x_minus_1_ps) { | |
154 | debug("CL = %u ok on DIMM %u at tCK=%u ps with tckmin_x_minus_1_ps of %u\n", | |
155 | temp2, i, mclk_ps, | |
156 | tckmin_x_minus_1_ps); | |
157 | continue; | |
158 | } else { | |
159 | not_ok++; | |
160 | } | |
161 | } | |
162 | ||
163 | if (dimm_params[i].caslat_x_minus_2 == temp2) { | |
164 | unsigned int tckmin_x_minus_2_ps | |
165 | = dimm_params[i].tckmin_x_minus_2_ps; | |
166 | if (mclk_ps >= tckmin_x_minus_2_ps) { | |
167 | debug("CL = %u ok on DIMM %u at tCK=%u ps with tckmin_x_minus_2_ps of %u\n", | |
168 | temp2, i, mclk_ps, | |
169 | tckmin_x_minus_2_ps); | |
170 | continue; | |
171 | } else { | |
172 | not_ok++; | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | if (!not_ok) | |
178 | lowest_good_caslat = temp2; | |
179 | ||
180 | temp1 &= ~(1 << temp2); | |
181 | } | |
182 | ||
183 | debug("lowest common SPD-defined CAS latency = %u\n", | |
184 | lowest_good_caslat); | |
185 | outpdimm->lowest_common_spd_caslat = lowest_good_caslat; | |
186 | ||
187 | ||
188 | /* | |
189 | * Compute a common 'de-rated' CAS latency. | |
190 | * | |
191 | * The strategy here is to find the *highest* dereated cas latency | |
192 | * with the assumption that all of the DIMMs will support a dereated | |
193 | * CAS latency higher than or equal to their lowest dereated value. | |
194 | */ | |
195 | temp1 = 0; | |
196 | for (i = 0; i < number_of_dimms; i++) | |
197 | temp1 = max(temp1, dimm_params[i].caslat_lowest_derated); | |
198 | ||
199 | outpdimm->highest_common_derated_caslat = temp1; | |
200 | debug("highest common dereated CAS latency = %u\n", temp1); | |
c360ceac DL |
201 | |
202 | return 0; | |
203 | } | |
2ed2e912 | 204 | #endif |
c360ceac | 205 | |
58e5e9af KG |
206 | /* |
207 | * compute_lowest_common_dimm_parameters() | |
208 | * | |
209 | * Determine the worst-case DIMM timing parameters from the set of DIMMs | |
210 | * whose parameters have been computed into the array pointed to | |
211 | * by dimm_params. | |
212 | */ | |
213 | unsigned int | |
03e664d8 YS |
214 | compute_lowest_common_dimm_parameters(const unsigned int ctrl_num, |
215 | const dimm_params_t *dimm_params, | |
58e5e9af | 216 | common_timing_params_t *outpdimm, |
123922b1 | 217 | const unsigned int number_of_dimms) |
58e5e9af | 218 | { |
9490ff48 | 219 | unsigned int i, j; |
58e5e9af | 220 | |
0dd38a35 PJ |
221 | unsigned int tckmin_x_ps = 0; |
222 | unsigned int tckmax_ps = 0xFFFFFFFF; | |
0dd38a35 PJ |
223 | unsigned int trcd_ps = 0; |
224 | unsigned int trp_ps = 0; | |
225 | unsigned int tras_ps = 0; | |
34e026f9 YS |
226 | #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) |
227 | unsigned int taamin_ps = 0; | |
228 | #endif | |
229 | #ifdef CONFIG_SYS_FSL_DDR4 | |
230 | unsigned int twr_ps = 15000; | |
231 | unsigned int trfc1_ps = 0; | |
232 | unsigned int trfc2_ps = 0; | |
233 | unsigned int trfc4_ps = 0; | |
234 | unsigned int trrds_ps = 0; | |
235 | unsigned int trrdl_ps = 0; | |
236 | unsigned int tccdl_ps = 0; | |
237 | #else | |
0dd38a35 PJ |
238 | unsigned int twr_ps = 0; |
239 | unsigned int twtr_ps = 0; | |
240 | unsigned int trfc_ps = 0; | |
241 | unsigned int trrd_ps = 0; | |
34e026f9 YS |
242 | unsigned int trtp_ps = 0; |
243 | #endif | |
0dd38a35 | 244 | unsigned int trc_ps = 0; |
58e5e9af | 245 | unsigned int refresh_rate_ps = 0; |
7e157b0a | 246 | unsigned int extended_op_srt = 1; |
34e026f9 | 247 | #if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2) |
0dd38a35 PJ |
248 | unsigned int tis_ps = 0; |
249 | unsigned int tih_ps = 0; | |
250 | unsigned int tds_ps = 0; | |
251 | unsigned int tdh_ps = 0; | |
0dd38a35 PJ |
252 | unsigned int tdqsq_max_ps = 0; |
253 | unsigned int tqhs_ps = 0; | |
34e026f9 | 254 | #endif |
dd127689 | 255 | unsigned int temp1, temp2; |
58e5e9af | 256 | unsigned int additive_latency = 0; |
58e5e9af KG |
257 | |
258 | temp1 = 0; | |
259 | for (i = 0; i < number_of_dimms; i++) { | |
260 | /* | |
261 | * If there are no ranks on this DIMM, | |
262 | * it probably doesn't exist, so skip it. | |
263 | */ | |
264 | if (dimm_params[i].n_ranks == 0) { | |
265 | temp1++; | |
266 | continue; | |
267 | } | |
5800e7ab YS |
268 | if (dimm_params[i].n_ranks == 4 && i != 0) { |
269 | printf("Found Quad-rank DIMM in wrong bank, ignored." | |
270 | " Software may not run as expected.\n"); | |
271 | temp1++; | |
272 | continue; | |
273 | } | |
123922b1 YS |
274 | |
275 | /* | |
276 | * check if quad-rank DIMM is plugged if | |
277 | * CONFIG_CHIP_SELECT_QUAD_CAPABLE is not defined | |
278 | * Only the board with proper design is capable | |
279 | */ | |
280 | #ifndef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE | |
5800e7ab YS |
281 | if (dimm_params[i].n_ranks == 4 && \ |
282 | CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) { | |
283 | printf("Found Quad-rank DIMM, not able to support."); | |
284 | temp1++; | |
285 | continue; | |
286 | } | |
123922b1 | 287 | #endif |
58e5e9af | 288 | /* |
0dd38a35 | 289 | * Find minimum tckmax_ps to find fastest slow speed, |
58e5e9af KG |
290 | * i.e., this is the slowest the whole system can go. |
291 | */ | |
b4141195 MY |
292 | tckmax_ps = min(tckmax_ps, |
293 | (unsigned int)dimm_params[i].tckmax_ps); | |
34e026f9 | 294 | #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) |
b4141195 MY |
295 | taamin_ps = max(taamin_ps, |
296 | (unsigned int)dimm_params[i].taa_ps); | |
34e026f9 | 297 | #endif |
b4141195 MY |
298 | tckmin_x_ps = max(tckmin_x_ps, |
299 | (unsigned int)dimm_params[i].tckmin_x_ps); | |
300 | trcd_ps = max(trcd_ps, (unsigned int)dimm_params[i].trcd_ps); | |
301 | trp_ps = max(trp_ps, (unsigned int)dimm_params[i].trp_ps); | |
302 | tras_ps = max(tras_ps, (unsigned int)dimm_params[i].tras_ps); | |
34e026f9 | 303 | #ifdef CONFIG_SYS_FSL_DDR4 |
b4141195 MY |
304 | trfc1_ps = max(trfc1_ps, |
305 | (unsigned int)dimm_params[i].trfc1_ps); | |
306 | trfc2_ps = max(trfc2_ps, | |
307 | (unsigned int)dimm_params[i].trfc2_ps); | |
308 | trfc4_ps = max(trfc4_ps, | |
309 | (unsigned int)dimm_params[i].trfc4_ps); | |
310 | trrds_ps = max(trrds_ps, | |
311 | (unsigned int)dimm_params[i].trrds_ps); | |
312 | trrdl_ps = max(trrdl_ps, | |
313 | (unsigned int)dimm_params[i].trrdl_ps); | |
314 | tccdl_ps = max(tccdl_ps, | |
315 | (unsigned int)dimm_params[i].tccdl_ps); | |
34e026f9 | 316 | #else |
b4141195 MY |
317 | twr_ps = max(twr_ps, (unsigned int)dimm_params[i].twr_ps); |
318 | twtr_ps = max(twtr_ps, (unsigned int)dimm_params[i].twtr_ps); | |
319 | trfc_ps = max(trfc_ps, (unsigned int)dimm_params[i].trfc_ps); | |
320 | trrd_ps = max(trrd_ps, (unsigned int)dimm_params[i].trrd_ps); | |
321 | trtp_ps = max(trtp_ps, (unsigned int)dimm_params[i].trtp_ps); | |
34e026f9 | 322 | #endif |
b4141195 | 323 | trc_ps = max(trc_ps, (unsigned int)dimm_params[i].trc_ps); |
34e026f9 | 324 | #if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2) |
b4141195 MY |
325 | tis_ps = max(tis_ps, (unsigned int)dimm_params[i].tis_ps); |
326 | tih_ps = max(tih_ps, (unsigned int)dimm_params[i].tih_ps); | |
327 | tds_ps = max(tds_ps, (unsigned int)dimm_params[i].tds_ps); | |
328 | tdh_ps = max(tdh_ps, (unsigned int)dimm_params[i].tdh_ps); | |
329 | tqhs_ps = max(tqhs_ps, (unsigned int)dimm_params[i].tqhs_ps); | |
58e5e9af | 330 | /* |
0dd38a35 | 331 | * Find maximum tdqsq_max_ps to find slowest. |
58e5e9af KG |
332 | * |
333 | * FIXME: is finding the slowest value the correct | |
334 | * strategy for this parameter? | |
335 | */ | |
b4141195 MY |
336 | tdqsq_max_ps = max(tdqsq_max_ps, |
337 | (unsigned int)dimm_params[i].tdqsq_max_ps); | |
34e026f9 YS |
338 | #endif |
339 | refresh_rate_ps = max(refresh_rate_ps, | |
b4141195 | 340 | (unsigned int)dimm_params[i].refresh_rate_ps); |
34e026f9 YS |
341 | /* extended_op_srt is either 0 or 1, 0 having priority */ |
342 | extended_op_srt = min(extended_op_srt, | |
b4141195 | 343 | (unsigned int)dimm_params[i].extended_op_srt); |
58e5e9af KG |
344 | } |
345 | ||
346 | outpdimm->ndimms_present = number_of_dimms - temp1; | |
347 | ||
348 | if (temp1 == number_of_dimms) { | |
349 | debug("no dimms this memory controller\n"); | |
350 | return 0; | |
351 | } | |
352 | ||
0dd38a35 PJ |
353 | outpdimm->tckmin_x_ps = tckmin_x_ps; |
354 | outpdimm->tckmax_ps = tckmax_ps; | |
34e026f9 YS |
355 | #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) |
356 | outpdimm->taamin_ps = taamin_ps; | |
357 | #endif | |
0dd38a35 PJ |
358 | outpdimm->trcd_ps = trcd_ps; |
359 | outpdimm->trp_ps = trp_ps; | |
360 | outpdimm->tras_ps = tras_ps; | |
34e026f9 YS |
361 | #ifdef CONFIG_SYS_FSL_DDR4 |
362 | outpdimm->trfc1_ps = trfc1_ps; | |
363 | outpdimm->trfc2_ps = trfc2_ps; | |
364 | outpdimm->trfc4_ps = trfc4_ps; | |
365 | outpdimm->trrds_ps = trrds_ps; | |
366 | outpdimm->trrdl_ps = trrdl_ps; | |
367 | outpdimm->tccdl_ps = tccdl_ps; | |
368 | #else | |
0dd38a35 PJ |
369 | outpdimm->twtr_ps = twtr_ps; |
370 | outpdimm->trfc_ps = trfc_ps; | |
371 | outpdimm->trrd_ps = trrd_ps; | |
34e026f9 YS |
372 | outpdimm->trtp_ps = trtp_ps; |
373 | #endif | |
374 | outpdimm->twr_ps = twr_ps; | |
0dd38a35 | 375 | outpdimm->trc_ps = trc_ps; |
58e5e9af | 376 | outpdimm->refresh_rate_ps = refresh_rate_ps; |
7e157b0a | 377 | outpdimm->extended_op_srt = extended_op_srt; |
34e026f9 | 378 | #if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2) |
0dd38a35 PJ |
379 | outpdimm->tis_ps = tis_ps; |
380 | outpdimm->tih_ps = tih_ps; | |
381 | outpdimm->tds_ps = tds_ps; | |
382 | outpdimm->tdh_ps = tdh_ps; | |
0dd38a35 PJ |
383 | outpdimm->tdqsq_max_ps = tdqsq_max_ps; |
384 | outpdimm->tqhs_ps = tqhs_ps; | |
34e026f9 | 385 | #endif |
58e5e9af KG |
386 | |
387 | /* Determine common burst length for all DIMMs. */ | |
388 | temp1 = 0xff; | |
389 | for (i = 0; i < number_of_dimms; i++) { | |
390 | if (dimm_params[i].n_ranks) { | |
391 | temp1 &= dimm_params[i].burst_lengths_bitmask; | |
392 | } | |
393 | } | |
0dd38a35 | 394 | outpdimm->all_dimms_burst_lengths_bitmask = temp1; |
58e5e9af KG |
395 | |
396 | /* Determine if all DIMMs registered buffered. */ | |
397 | temp1 = temp2 = 0; | |
398 | for (i = 0; i < number_of_dimms; i++) { | |
399 | if (dimm_params[i].n_ranks) { | |
c399765d | 400 | if (dimm_params[i].registered_dimm) { |
58e5e9af | 401 | temp1 = 1; |
bb0dc108 | 402 | #ifndef CONFIG_SPL_BUILD |
c399765d YS |
403 | printf("Detected RDIMM %s\n", |
404 | dimm_params[i].mpart); | |
bb0dc108 | 405 | #endif |
c399765d | 406 | } else { |
58e5e9af | 407 | temp2 = 1; |
bb0dc108 | 408 | #ifndef CONFIG_SPL_BUILD |
c399765d YS |
409 | printf("Detected UDIMM %s\n", |
410 | dimm_params[i].mpart); | |
bb0dc108 | 411 | #endif |
c399765d | 412 | } |
58e5e9af KG |
413 | } |
414 | } | |
415 | ||
0dd38a35 PJ |
416 | outpdimm->all_dimms_registered = 0; |
417 | outpdimm->all_dimms_unbuffered = 0; | |
58e5e9af | 418 | if (temp1 && !temp2) { |
0dd38a35 | 419 | outpdimm->all_dimms_registered = 1; |
dd127689 | 420 | } else if (!temp1 && temp2) { |
0dd38a35 | 421 | outpdimm->all_dimms_unbuffered = 1; |
dd127689 | 422 | } else { |
58e5e9af KG |
423 | printf("ERROR: Mix of registered buffered and unbuffered " |
424 | "DIMMs detected!\n"); | |
425 | } | |
426 | ||
9490ff48 | 427 | temp1 = 0; |
0dd38a35 | 428 | if (outpdimm->all_dimms_registered) |
9490ff48 YS |
429 | for (j = 0; j < 16; j++) { |
430 | outpdimm->rcw[j] = dimm_params[0].rcw[j]; | |
123922b1 YS |
431 | for (i = 1; i < number_of_dimms; i++) { |
432 | if (!dimm_params[i].n_ranks) | |
433 | continue; | |
9490ff48 | 434 | if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) { |
dd127689 | 435 | temp1 = 1; |
9490ff48 YS |
436 | break; |
437 | } | |
123922b1 | 438 | } |
9490ff48 YS |
439 | } |
440 | ||
441 | if (temp1 != 0) | |
442 | printf("ERROR: Mix different RDIMM detected!\n"); | |
443 | ||
34e026f9 | 444 | /* calculate cas latency for all DDR types */ |
03e664d8 YS |
445 | if (compute_cas_latency(ctrl_num, dimm_params, |
446 | outpdimm, number_of_dimms)) | |
c360ceac | 447 | return 1; |
58e5e9af KG |
448 | |
449 | /* Determine if all DIMMs ECC capable. */ | |
450 | temp1 = 1; | |
451 | for (i = 0; i < number_of_dimms; i++) { | |
08b3f759 YS |
452 | if (dimm_params[i].n_ranks && |
453 | !(dimm_params[i].edc_config & EDC_ECC)) { | |
58e5e9af KG |
454 | temp1 = 0; |
455 | break; | |
456 | } | |
457 | } | |
458 | if (temp1) { | |
459 | debug("all DIMMs ECC capable\n"); | |
460 | } else { | |
461 | debug("Warning: not all DIMMs ECC capable, cant enable ECC\n"); | |
462 | } | |
0dd38a35 | 463 | outpdimm->all_dimms_ecc_capable = temp1; |
58e5e9af | 464 | |
58e5e9af KG |
465 | /* |
466 | * Compute additive latency. | |
467 | * | |
468 | * For DDR1, additive latency should be 0. | |
469 | * | |
470 | * For DDR2, with ODT enabled, use "a value" less than ACTTORW, | |
471 | * which comes from Trcd, and also note that: | |
472 | * add_lat + caslat must be >= 4 | |
473 | * | |
c360ceac | 474 | * For DDR3, we use the AL=0 |
58e5e9af KG |
475 | * |
476 | * When to use additive latency for DDR2: | |
477 | * | |
478 | * I. Because you are using CL=3 and need to do ODT on writes and | |
479 | * want functionality. | |
480 | * 1. Are you going to use ODT? (Does your board not have | |
481 | * additional termination circuitry for DQ, DQS, DQS_, | |
482 | * DM, RDQS, RDQS_ for x4/x8 configs?) | |
483 | * 2. If so, is your lowest supported CL going to be 3? | |
484 | * 3. If so, then you must set AL=1 because | |
485 | * | |
486 | * WL >= 3 for ODT on writes | |
487 | * RL = AL + CL | |
488 | * WL = RL - 1 | |
489 | * -> | |
490 | * WL = AL + CL - 1 | |
491 | * AL + CL - 1 >= 3 | |
492 | * AL + CL >= 4 | |
493 | * QED | |
494 | * | |
495 | * RL >= 3 for ODT on reads | |
496 | * RL = AL + CL | |
497 | * | |
498 | * Since CL aren't usually less than 2, AL=0 is a minimum, | |
499 | * so the WL-derived AL should be the -- FIXME? | |
500 | * | |
501 | * II. Because you are using auto-precharge globally and want to | |
502 | * use additive latency (posted CAS) to get more bandwidth. | |
503 | * 1. Are you going to use auto-precharge mode globally? | |
504 | * | |
505 | * Use addtivie latency and compute AL to be 1 cycle less than | |
506 | * tRCD, i.e. the READ or WRITE command is in the cycle | |
507 | * immediately following the ACTIVATE command.. | |
508 | * | |
509 | * III. Because you feel like it or want to do some sort of | |
510 | * degraded-performance experiment. | |
511 | * 1. Do you just want to use additive latency because you feel | |
512 | * like it? | |
513 | * | |
514 | * Validation: AL is less than tRCD, and within the other | |
515 | * read-to-precharge constraints. | |
516 | */ | |
517 | ||
518 | additive_latency = 0; | |
519 | ||
5614e71b | 520 | #if defined(CONFIG_SYS_FSL_DDR2) |
34e026f9 | 521 | if ((outpdimm->lowest_common_spd_caslat < 4) && |
03e664d8 YS |
522 | (picos_to_mclk(ctrl_num, trcd_ps) > |
523 | outpdimm->lowest_common_spd_caslat)) { | |
524 | additive_latency = picos_to_mclk(ctrl_num, trcd_ps) - | |
34e026f9 | 525 | outpdimm->lowest_common_spd_caslat; |
03e664d8 YS |
526 | if (mclk_to_picos(ctrl_num, additive_latency) > trcd_ps) { |
527 | additive_latency = picos_to_mclk(ctrl_num, trcd_ps); | |
58e5e9af KG |
528 | debug("setting additive_latency to %u because it was " |
529 | " greater than tRCD_ps\n", additive_latency); | |
530 | } | |
531 | } | |
58e5e9af KG |
532 | #endif |
533 | ||
534 | /* | |
535 | * Validate additive latency | |
58e5e9af KG |
536 | * |
537 | * AL <= tRCD(min) | |
538 | */ | |
03e664d8 | 539 | if (mclk_to_picos(ctrl_num, additive_latency) > trcd_ps) { |
58e5e9af KG |
540 | printf("Error: invalid additive latency exceeds tRCD(min).\n"); |
541 | return 1; | |
542 | } | |
543 | ||
544 | /* | |
545 | * RL = CL + AL; RL >= 3 for ODT_RD_CFG to be enabled | |
546 | * WL = RL - 1; WL >= 3 for ODT_WL_CFG to be enabled | |
547 | * ADD_LAT (the register) must be set to a value less | |
548 | * than ACTTORW if WL = 1, then AL must be set to 1 | |
549 | * RD_TO_PRE (the register) must be set to a minimum | |
550 | * tRTP + AL if AL is nonzero | |
551 | */ | |
552 | ||
553 | /* | |
554 | * Additive latency will be applied only if the memctl option to | |
555 | * use it. | |
556 | */ | |
557 | outpdimm->additive_latency = additive_latency; | |
558 | ||
0dd38a35 PJ |
559 | debug("tCKmin_ps = %u\n", outpdimm->tckmin_x_ps); |
560 | debug("trcd_ps = %u\n", outpdimm->trcd_ps); | |
561 | debug("trp_ps = %u\n", outpdimm->trp_ps); | |
562 | debug("tras_ps = %u\n", outpdimm->tras_ps); | |
34e026f9 YS |
563 | #ifdef CONFIG_SYS_FSL_DDR4 |
564 | debug("trfc1_ps = %u\n", trfc1_ps); | |
565 | debug("trfc2_ps = %u\n", trfc2_ps); | |
566 | debug("trfc4_ps = %u\n", trfc4_ps); | |
567 | debug("trrds_ps = %u\n", trrds_ps); | |
568 | debug("trrdl_ps = %u\n", trrdl_ps); | |
569 | debug("tccdl_ps = %u\n", tccdl_ps); | |
570 | #else | |
0dd38a35 PJ |
571 | debug("twtr_ps = %u\n", outpdimm->twtr_ps); |
572 | debug("trfc_ps = %u\n", outpdimm->trfc_ps); | |
573 | debug("trrd_ps = %u\n", outpdimm->trrd_ps); | |
34e026f9 YS |
574 | #endif |
575 | debug("twr_ps = %u\n", outpdimm->twr_ps); | |
0dd38a35 | 576 | debug("trc_ps = %u\n", outpdimm->trc_ps); |
45064adc | 577 | |
58e5e9af KG |
578 | return 0; |
579 | } |