]>
Commit | Line | Data |
---|---|---|
58e5e9af | 1 | /* |
fc0c2b6f | 2 | * Copyright 2008-2011 Freescale Semiconductor, Inc. |
58e5e9af KG |
3 | * |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * Version 2 as published by the Free Software Foundation. | |
7 | */ | |
8 | ||
9 | /* | |
10 | * Generic driver for Freescale DDR/DDR2/DDR3 memory controller. | |
11 | * Based on code from spd_sdram.c | |
12 | * Author: James Yang [at freescale.com] | |
13 | */ | |
14 | ||
15 | #include <common.h> | |
c39f44dc | 16 | #include <i2c.h> |
58e5e9af KG |
17 | #include <asm/fsl_ddr_sdram.h> |
18 | ||
19 | #include "ddr.h" | |
20 | ||
21 | extern void fsl_ddr_set_lawbar( | |
22 | const common_timing_params_t *memctl_common_params, | |
23 | unsigned int memctl_interleaved, | |
24 | unsigned int ctrl_num); | |
25 | ||
26 | /* processor specific function */ | |
27 | extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, | |
28 | unsigned int ctrl_num); | |
29 | ||
c39f44dc KG |
30 | #if defined(SPD_EEPROM_ADDRESS) || \ |
31 | defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \ | |
32 | defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4) | |
33 | #if (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) | |
34 | u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { | |
35 | [0][0] = SPD_EEPROM_ADDRESS, | |
36 | }; | |
639f330f YS |
37 | #elif (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) |
38 | u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { | |
39 | [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ | |
40 | [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */ | |
41 | }; | |
42 | #elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) | |
c39f44dc KG |
43 | u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { |
44 | [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ | |
45 | [1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */ | |
46 | }; | |
639f330f | 47 | #elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) |
c39f44dc KG |
48 | u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { |
49 | [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ | |
50 | [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */ | |
51 | [1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */ | |
52 | [1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */ | |
53 | }; | |
54 | #endif | |
55 | ||
56 | static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) | |
57 | { | |
58 | int ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, | |
59 | sizeof(generic_spd_eeprom_t)); | |
60 | ||
61 | if (ret) { | |
62 | printf("DDR: failed to read SPD from address %u\n", i2c_address); | |
63 | memset(spd, 0, sizeof(generic_spd_eeprom_t)); | |
64 | } | |
65 | } | |
66 | ||
67 | __attribute__((weak, alias("__get_spd"))) | |
68 | void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address); | |
69 | ||
70 | void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, | |
71 | unsigned int ctrl_num) | |
72 | { | |
73 | unsigned int i; | |
74 | unsigned int i2c_address = 0; | |
75 | ||
76 | if (ctrl_num >= CONFIG_NUM_DDR_CONTROLLERS) { | |
77 | printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); | |
78 | return; | |
79 | } | |
80 | ||
81 | for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { | |
82 | i2c_address = spd_i2c_addr[ctrl_num][i]; | |
83 | get_spd(&(ctrl_dimms_spd[i]), i2c_address); | |
84 | } | |
85 | } | |
86 | #else | |
87 | void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, | |
88 | unsigned int ctrl_num) | |
89 | { | |
90 | } | |
91 | #endif /* SPD_EEPROM_ADDRESSx */ | |
58e5e9af KG |
92 | |
93 | /* | |
94 | * ASSUMPTIONS: | |
95 | * - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller | |
96 | * - Same memory data bus width on all controllers | |
97 | * | |
98 | * NOTES: | |
99 | * | |
100 | * The memory controller and associated documentation use confusing | |
101 | * terminology when referring to the orgranization of DRAM. | |
102 | * | |
103 | * Here is a terminology translation table: | |
104 | * | |
105 | * memory controller/documention |industry |this code |signals | |
106 | * -------------------------------|-----------|-----------|----------------- | |
f12e4549 WD |
107 | * physical bank/bank |rank |rank |chip select (CS) |
108 | * logical bank/sub-bank |bank |bank |bank address (BA) | |
109 | * page/row |row |page |row address | |
110 | * ??? |column |column |column address | |
58e5e9af KG |
111 | * |
112 | * The naming confusion is further exacerbated by the descriptions of the | |
113 | * memory controller interleaving feature, where accesses are interleaved | |
114 | * _BETWEEN_ two seperate memory controllers. This is configured only in | |
115 | * CS0_CONFIG[INTLV_CTL] of each memory controller. | |
116 | * | |
117 | * memory controller documentation | number of chip selects | |
f12e4549 | 118 | * | per memory controller supported |
58e5e9af | 119 | * --------------------------------|----------------------------------------- |
f12e4549 WD |
120 | * cache line interleaving | 1 (CS0 only) |
121 | * page interleaving | 1 (CS0 only) | |
122 | * bank interleaving | 1 (CS0 only) | |
123 | * superbank interleraving | depends on bank (chip select) | |
124 | * | interleraving [rank interleaving] | |
125 | * | mode used on every memory controller | |
58e5e9af KG |
126 | * |
127 | * Even further confusing is the existence of the interleaving feature | |
128 | * _WITHIN_ each memory controller. The feature is referred to in | |
129 | * documentation as chip select interleaving or bank interleaving, | |
130 | * although it is configured in the DDR_SDRAM_CFG field. | |
131 | * | |
f12e4549 | 132 | * Name of field | documentation name | this code |
58e5e9af | 133 | * -----------------------------|-----------------------|------------------ |
f12e4549 WD |
134 | * DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving |
135 | * | interleaving | |
58e5e9af KG |
136 | */ |
137 | ||
58e5e9af KG |
138 | const char *step_string_tbl[] = { |
139 | "STEP_GET_SPD", | |
140 | "STEP_COMPUTE_DIMM_PARMS", | |
141 | "STEP_COMPUTE_COMMON_PARMS", | |
142 | "STEP_GATHER_OPTS", | |
143 | "STEP_ASSIGN_ADDRESSES", | |
144 | "STEP_COMPUTE_REGS", | |
145 | "STEP_PROGRAM_REGS", | |
146 | "STEP_ALL" | |
147 | }; | |
148 | ||
149 | const char * step_to_string(unsigned int step) { | |
150 | ||
151 | unsigned int s = __ilog2(step); | |
152 | ||
153 | if ((1 << s) != step) | |
154 | return step_string_tbl[7]; | |
155 | ||
156 | return step_string_tbl[s]; | |
157 | } | |
58e5e9af KG |
158 | |
159 | int step_assign_addresses(fsl_ddr_info_t *pinfo, | |
160 | unsigned int dbw_cap_adj[], | |
076bff8f YS |
161 | unsigned int *all_memctl_interleaving, |
162 | unsigned int *all_ctlr_rank_interleaving) | |
58e5e9af KG |
163 | { |
164 | int i, j; | |
165 | ||
166 | /* | |
167 | * If a reduced data width is requested, but the SPD | |
168 | * specifies a physically wider device, adjust the | |
169 | * computed dimm capacities accordingly before | |
170 | * assigning addresses. | |
171 | */ | |
172 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
173 | unsigned int found = 0; | |
174 | ||
175 | switch (pinfo->memctl_opts[i].data_bus_width) { | |
176 | case 2: | |
177 | /* 16-bit */ | |
51d498f1 YS |
178 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { |
179 | unsigned int dw; | |
180 | if (!pinfo->dimm_params[i][j].n_ranks) | |
181 | continue; | |
182 | dw = pinfo->dimm_params[i][j].primary_sdram_width; | |
183 | if ((dw == 72 || dw == 64)) { | |
184 | dbw_cap_adj[i] = 2; | |
185 | break; | |
186 | } else if ((dw == 40 || dw == 32)) { | |
187 | dbw_cap_adj[i] = 1; | |
188 | break; | |
189 | } | |
190 | } | |
58e5e9af KG |
191 | break; |
192 | ||
193 | case 1: | |
194 | /* 32-bit */ | |
195 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
196 | unsigned int dw; | |
197 | dw = pinfo->dimm_params[i][j].data_width; | |
198 | if (pinfo->dimm_params[i][j].n_ranks | |
199 | && (dw == 72 || dw == 64)) { | |
200 | /* | |
201 | * FIXME: can't really do it | |
202 | * like this because this just | |
203 | * further reduces the memory | |
204 | */ | |
205 | found = 1; | |
206 | break; | |
207 | } | |
208 | } | |
209 | if (found) { | |
210 | dbw_cap_adj[i] = 1; | |
211 | } | |
212 | break; | |
213 | ||
214 | case 0: | |
215 | /* 64-bit */ | |
216 | break; | |
217 | ||
218 | default: | |
219 | printf("unexpected data bus width " | |
220 | "specified controller %u\n", i); | |
221 | return 1; | |
222 | } | |
223 | } | |
224 | ||
58e5e9af | 225 | j = 0; |
076bff8f YS |
226 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) |
227 | if (pinfo->memctl_opts[i].memctl_interleaving) | |
58e5e9af | 228 | j++; |
076bff8f YS |
229 | /* |
230 | * Not support less than all memory controllers interleaving | |
231 | * if more than two controllers | |
232 | */ | |
233 | if (j == CONFIG_NUM_DDR_CONTROLLERS) | |
234 | *all_memctl_interleaving = 1; | |
c9ffd839 | 235 | |
58e5e9af KG |
236 | /* Check that all controllers are rank interleaving. */ |
237 | j = 0; | |
076bff8f YS |
238 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) |
239 | if (pinfo->memctl_opts[i].ba_intlv_ctl) | |
58e5e9af | 240 | j++; |
076bff8f YS |
241 | /* |
242 | * All memory controllers must be populated to qualify for | |
243 | * all controller rank interleaving | |
244 | */ | |
245 | if (j == CONFIG_NUM_DDR_CONTROLLERS) | |
246 | *all_ctlr_rank_interleaving = 1; | |
c9ffd839 | 247 | |
076bff8f | 248 | if (*all_memctl_interleaving) { |
e7563aff | 249 | unsigned long long addr, total_mem_per_ctlr = 0; |
58e5e9af KG |
250 | /* |
251 | * If interleaving between memory controllers, | |
252 | * make each controller start at a base address | |
253 | * of 0. | |
254 | * | |
255 | * Also, if bank interleaving (chip select | |
256 | * interleaving) is enabled on each memory | |
257 | * controller, CS0 needs to be programmed to | |
258 | * cover the entire memory range on that memory | |
259 | * controller | |
260 | * | |
261 | * Bank interleaving also implies that each | |
262 | * addressed chip select is identical in size. | |
263 | */ | |
264 | ||
265 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
266 | addr = 0; | |
e7563aff | 267 | pinfo->common_timing_params[i].base_address = 0ull; |
58e5e9af KG |
268 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { |
269 | unsigned long long cap | |
270 | = pinfo->dimm_params[i][j].capacity; | |
271 | ||
272 | pinfo->dimm_params[i][j].base_address = addr; | |
e7563aff | 273 | addr += cap >> dbw_cap_adj[i]; |
dbbbb3ab | 274 | total_mem_per_ctlr += cap >> dbw_cap_adj[i]; |
58e5e9af KG |
275 | } |
276 | } | |
dbbbb3ab | 277 | pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr; |
58e5e9af KG |
278 | } else { |
279 | /* | |
280 | * Simple linear assignment if memory | |
281 | * controllers are not interleaved. | |
282 | */ | |
e7563aff | 283 | unsigned long long cur_memsize = 0; |
58e5e9af | 284 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { |
e7563aff | 285 | u64 total_mem_per_ctlr = 0; |
58e5e9af | 286 | pinfo->common_timing_params[i].base_address = |
e7563aff | 287 | cur_memsize; |
58e5e9af KG |
288 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { |
289 | /* Compute DIMM base addresses. */ | |
290 | unsigned long long cap = | |
291 | pinfo->dimm_params[i][j].capacity; | |
58e5e9af | 292 | pinfo->dimm_params[i][j].base_address = |
e7563aff | 293 | cur_memsize; |
58e5e9af KG |
294 | cur_memsize += cap >> dbw_cap_adj[i]; |
295 | total_mem_per_ctlr += cap >> dbw_cap_adj[i]; | |
296 | } | |
297 | pinfo->common_timing_params[i].total_mem = | |
298 | total_mem_per_ctlr; | |
299 | } | |
300 | } | |
301 | ||
302 | return 0; | |
303 | } | |
304 | ||
e7563aff | 305 | unsigned long long |
fc0c2b6f HW |
306 | fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step, |
307 | unsigned int size_only) | |
58e5e9af KG |
308 | { |
309 | unsigned int i, j; | |
310 | unsigned int all_controllers_memctl_interleaving = 0; | |
311 | unsigned int all_controllers_rank_interleaving = 0; | |
e7563aff | 312 | unsigned long long total_mem = 0; |
58e5e9af KG |
313 | |
314 | fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; | |
315 | common_timing_params_t *timing_params = pinfo->common_timing_params; | |
316 | ||
317 | /* data bus width capacity adjust shift amount */ | |
318 | unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS]; | |
319 | ||
320 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
321 | dbw_capacity_adjust[i] = 0; | |
322 | } | |
323 | ||
324 | debug("starting at step %u (%s)\n", | |
325 | start_step, step_to_string(start_step)); | |
326 | ||
327 | switch (start_step) { | |
328 | case STEP_GET_SPD: | |
1b3e3c4f | 329 | #if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM) |
58e5e9af KG |
330 | /* STEP 1: Gather all DIMM SPD data */ |
331 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
332 | fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i); | |
333 | } | |
334 | ||
335 | case STEP_COMPUTE_DIMM_PARMS: | |
336 | /* STEP 2: Compute DIMM parameters from SPD data */ | |
337 | ||
338 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
339 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
340 | unsigned int retval; | |
341 | generic_spd_eeprom_t *spd = | |
342 | &(pinfo->spd_installed_dimms[i][j]); | |
343 | dimm_params_t *pdimm = | |
f12e4549 | 344 | &(pinfo->dimm_params[i][j]); |
58e5e9af KG |
345 | |
346 | retval = compute_dimm_parameters(spd, pdimm, i); | |
f2d264b6 YS |
347 | #ifdef CONFIG_SYS_DDR_RAW_TIMING |
348 | if (retval != 0) { | |
349 | printf("SPD error! Trying fallback to " | |
350 | "raw timing calculation\n"); | |
351 | fsl_ddr_get_dimm_params(pdimm, i, j); | |
352 | } | |
353 | #else | |
58e5e9af KG |
354 | if (retval == 2) { |
355 | printf("Error: compute_dimm_parameters" | |
356 | " non-zero returned FATAL value " | |
357 | "for memctl=%u dimm=%u\n", i, j); | |
358 | return 0; | |
359 | } | |
f2d264b6 | 360 | #endif |
58e5e9af KG |
361 | if (retval) { |
362 | debug("Warning: compute_dimm_parameters" | |
363 | " non-zero return value for memctl=%u " | |
364 | "dimm=%u\n", i, j); | |
365 | } | |
366 | } | |
367 | } | |
368 | ||
1b3e3c4f YS |
369 | #else |
370 | case STEP_COMPUTE_DIMM_PARMS: | |
371 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
372 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
373 | dimm_params_t *pdimm = | |
374 | &(pinfo->dimm_params[i][j]); | |
375 | fsl_ddr_get_dimm_params(pdimm, i, j); | |
376 | } | |
377 | } | |
378 | debug("Filling dimm parameters from board specific file\n"); | |
379 | #endif | |
58e5e9af KG |
380 | case STEP_COMPUTE_COMMON_PARMS: |
381 | /* | |
382 | * STEP 3: Compute a common set of timing parameters | |
383 | * suitable for all of the DIMMs on each memory controller | |
384 | */ | |
385 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
386 | debug("Computing lowest common DIMM" | |
387 | " parameters for memctl=%u\n", i); | |
388 | compute_lowest_common_dimm_parameters( | |
389 | pinfo->dimm_params[i], | |
390 | &timing_params[i], | |
391 | CONFIG_DIMM_SLOTS_PER_CTLR); | |
392 | } | |
393 | ||
394 | case STEP_GATHER_OPTS: | |
395 | /* STEP 4: Gather configuration requirements from user */ | |
396 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
397 | debug("Reloading memory controller " | |
398 | "configuration options for memctl=%u\n", i); | |
399 | /* | |
400 | * This "reloads" the memory controller options | |
401 | * to defaults. If the user "edits" an option, | |
402 | * next_step points to the step after this, | |
403 | * which is currently STEP_ASSIGN_ADDRESSES. | |
404 | */ | |
405 | populate_memctl_options( | |
406 | timing_params[i].all_DIMMs_registered, | |
dfb49108 HW |
407 | &pinfo->memctl_opts[i], |
408 | pinfo->dimm_params[i], i); | |
58e5e9af | 409 | } |
076bff8f | 410 | check_interleaving_options(pinfo); |
58e5e9af KG |
411 | case STEP_ASSIGN_ADDRESSES: |
412 | /* STEP 5: Assign addresses to chip selects */ | |
413 | step_assign_addresses(pinfo, | |
414 | dbw_capacity_adjust, | |
415 | &all_controllers_memctl_interleaving, | |
416 | &all_controllers_rank_interleaving); | |
417 | ||
418 | case STEP_COMPUTE_REGS: | |
419 | /* STEP 6: compute controller register values */ | |
420 | debug("FSL Memory ctrl cg register computation\n"); | |
421 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
422 | if (timing_params[i].ndimms_present == 0) { | |
423 | memset(&ddr_reg[i], 0, | |
424 | sizeof(fsl_ddr_cfg_regs_t)); | |
425 | continue; | |
426 | } | |
427 | ||
428 | compute_fsl_memctl_config_regs( | |
429 | &pinfo->memctl_opts[i], | |
430 | &ddr_reg[i], &timing_params[i], | |
431 | pinfo->dimm_params[i], | |
fc0c2b6f HW |
432 | dbw_capacity_adjust[i], |
433 | size_only); | |
58e5e9af KG |
434 | } |
435 | ||
436 | default: | |
437 | break; | |
438 | } | |
439 | ||
440 | /* Compute the total amount of memory. */ | |
441 | ||
442 | /* | |
443 | * If bank interleaving but NOT memory controller interleaving | |
444 | * CS_BNDS describe the quantity of memory on each memory | |
445 | * controller, so the total is the sum across. | |
446 | */ | |
447 | if (!all_controllers_memctl_interleaving | |
448 | && all_controllers_rank_interleaving) { | |
449 | total_mem = 0; | |
450 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
451 | total_mem += timing_params[i].total_mem; | |
452 | } | |
453 | ||
454 | } else { | |
455 | /* | |
456 | * Compute the amount of memory available just by | |
457 | * looking for the highest valid CSn_BNDS value. | |
458 | * This allows us to also experiment with using | |
459 | * only CS0 when using dual-rank DIMMs. | |
460 | */ | |
461 | unsigned int max_end = 0; | |
462 | ||
463 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
464 | for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) { | |
465 | fsl_ddr_cfg_regs_t *reg = &ddr_reg[i]; | |
466 | if (reg->cs[j].config & 0x80000000) { | |
467 | unsigned int end; | |
468 | end = reg->cs[j].bnds & 0xFFF; | |
469 | if (end > max_end) { | |
470 | max_end = end; | |
471 | } | |
472 | } | |
473 | } | |
474 | } | |
475 | ||
58e5e9af KG |
476 | total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
477 | | 0xFFFFFFULL); | |
478 | } | |
479 | ||
480 | return total_mem; | |
481 | } | |
482 | ||
483 | /* | |
484 | * fsl_ddr_sdram() -- this is the main function to be called by | |
485 | * initdram() in the board file. | |
486 | * | |
487 | * It returns amount of memory configured in bytes. | |
488 | */ | |
489 | phys_size_t fsl_ddr_sdram(void) | |
490 | { | |
491 | unsigned int i; | |
492 | unsigned int memctl_interleaved; | |
e7563aff | 493 | unsigned long long total_memory; |
58e5e9af KG |
494 | fsl_ddr_info_t info; |
495 | ||
496 | /* Reset info structure. */ | |
497 | memset(&info, 0, sizeof(fsl_ddr_info_t)); | |
498 | ||
499 | /* Compute it once normally. */ | |
6f5e1dc5 YS |
500 | #ifdef CONFIG_FSL_DDR_INTERACTIVE |
501 | if (getenv("ddr_interactive")) | |
502 | total_memory = fsl_ddr_interactive(&info); | |
503 | else | |
504 | #endif | |
505 | total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0); | |
58e5e9af KG |
506 | |
507 | /* Check for memory controller interleaving. */ | |
508 | memctl_interleaved = 0; | |
509 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
510 | memctl_interleaved += | |
511 | info.memctl_opts[i].memctl_interleaving; | |
512 | } | |
513 | ||
514 | if (memctl_interleaved) { | |
515 | if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) { | |
516 | debug("memctl interleaving\n"); | |
517 | /* | |
518 | * Change the meaning of memctl_interleaved | |
519 | * to be "boolean". | |
520 | */ | |
521 | memctl_interleaved = 1; | |
522 | } else { | |
7008d26a | 523 | printf("Warning: memctl interleaving not " |
58e5e9af | 524 | "properly configured on all controllers\n"); |
7008d26a ES |
525 | memctl_interleaved = 0; |
526 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) | |
527 | info.memctl_opts[i].memctl_interleaving = 0; | |
528 | debug("Recomputing with memctl_interleaving off.\n"); | |
529 | total_memory = fsl_ddr_compute(&info, | |
fc0c2b6f HW |
530 | STEP_ASSIGN_ADDRESSES, |
531 | 0); | |
58e5e9af KG |
532 | } |
533 | } | |
534 | ||
535 | /* Program configuration registers. */ | |
536 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
537 | debug("Programming controller %u\n", i); | |
538 | if (info.common_timing_params[i].ndimms_present == 0) { | |
539 | debug("No dimms present on controller %u; " | |
540 | "skipping programming\n", i); | |
541 | continue; | |
542 | } | |
543 | ||
544 | fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i); | |
545 | } | |
546 | ||
547 | if (memctl_interleaved) { | |
548 | const unsigned int ctrl_num = 0; | |
549 | ||
550 | /* Only set LAWBAR1 if memory controller interleaving is on. */ | |
551 | fsl_ddr_set_lawbar(&info.common_timing_params[0], | |
552 | memctl_interleaved, ctrl_num); | |
553 | } else { | |
554 | /* | |
555 | * Memory controller interleaving is NOT on; | |
556 | * set each lawbar individually. | |
557 | */ | |
558 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
559 | fsl_ddr_set_lawbar(&info.common_timing_params[i], | |
560 | 0, i); | |
561 | } | |
562 | } | |
563 | ||
e7563aff KG |
564 | debug("total_memory = %llu\n", total_memory); |
565 | ||
566 | #if !defined(CONFIG_PHYS_64BIT) | |
567 | /* Check for 4G or more. Bad. */ | |
568 | if (total_memory >= (1ull << 32)) { | |
569 | printf("Detected %lld MB of memory\n", total_memory >> 20); | |
7ea3871e BB |
570 | printf(" This U-Boot only supports < 4G of DDR\n"); |
571 | printf(" You could rebuild it with CONFIG_PHYS_64BIT\n"); | |
572 | printf(" "); /* re-align to match init_func_ram print */ | |
e7563aff KG |
573 | total_memory = CONFIG_MAX_MEM_MAPPED; |
574 | } | |
575 | #endif | |
58e5e9af KG |
576 | |
577 | return total_memory; | |
578 | } | |
fc0c2b6f HW |
579 | |
580 | /* | |
581 | * fsl_ddr_sdram_size() - This function only returns the size of the total | |
582 | * memory without setting ddr control registers. | |
583 | */ | |
584 | phys_size_t | |
585 | fsl_ddr_sdram_size(void) | |
586 | { | |
587 | fsl_ddr_info_t info; | |
588 | unsigned long long total_memory = 0; | |
589 | ||
590 | memset(&info, 0 , sizeof(fsl_ddr_info_t)); | |
591 | ||
592 | /* Compute it once normally. */ | |
593 | total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1); | |
594 | ||
595 | return total_memory; | |
596 | } |