]>
Commit | Line | Data |
---|---|---|
58e5e9af KG |
1 | /* |
2 | * Copyright 2008 Freescale Semiconductor, Inc. | |
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> | |
16 | #include <asm/fsl_ddr_sdram.h> | |
17 | ||
18 | #include "ddr.h" | |
19 | ||
20 | extern void fsl_ddr_set_lawbar( | |
21 | const common_timing_params_t *memctl_common_params, | |
22 | unsigned int memctl_interleaved, | |
23 | unsigned int ctrl_num); | |
24 | ||
25 | /* processor specific function */ | |
26 | extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, | |
27 | unsigned int ctrl_num); | |
28 | ||
29 | /* Board-specific functions defined in each board's ddr.c */ | |
30 | extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, | |
31 | unsigned int ctrl_num); | |
32 | ||
33 | /* | |
34 | * ASSUMPTIONS: | |
35 | * - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller | |
36 | * - Same memory data bus width on all controllers | |
37 | * | |
38 | * NOTES: | |
39 | * | |
40 | * The memory controller and associated documentation use confusing | |
41 | * terminology when referring to the orgranization of DRAM. | |
42 | * | |
43 | * Here is a terminology translation table: | |
44 | * | |
45 | * memory controller/documention |industry |this code |signals | |
46 | * -------------------------------|-----------|-----------|----------------- | |
f12e4549 WD |
47 | * physical bank/bank |rank |rank |chip select (CS) |
48 | * logical bank/sub-bank |bank |bank |bank address (BA) | |
49 | * page/row |row |page |row address | |
50 | * ??? |column |column |column address | |
58e5e9af KG |
51 | * |
52 | * The naming confusion is further exacerbated by the descriptions of the | |
53 | * memory controller interleaving feature, where accesses are interleaved | |
54 | * _BETWEEN_ two seperate memory controllers. This is configured only in | |
55 | * CS0_CONFIG[INTLV_CTL] of each memory controller. | |
56 | * | |
57 | * memory controller documentation | number of chip selects | |
f12e4549 | 58 | * | per memory controller supported |
58e5e9af | 59 | * --------------------------------|----------------------------------------- |
f12e4549 WD |
60 | * cache line interleaving | 1 (CS0 only) |
61 | * page interleaving | 1 (CS0 only) | |
62 | * bank interleaving | 1 (CS0 only) | |
63 | * superbank interleraving | depends on bank (chip select) | |
64 | * | interleraving [rank interleaving] | |
65 | * | mode used on every memory controller | |
58e5e9af KG |
66 | * |
67 | * Even further confusing is the existence of the interleaving feature | |
68 | * _WITHIN_ each memory controller. The feature is referred to in | |
69 | * documentation as chip select interleaving or bank interleaving, | |
70 | * although it is configured in the DDR_SDRAM_CFG field. | |
71 | * | |
f12e4549 | 72 | * Name of field | documentation name | this code |
58e5e9af | 73 | * -----------------------------|-----------------------|------------------ |
f12e4549 WD |
74 | * DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving |
75 | * | interleaving | |
58e5e9af KG |
76 | */ |
77 | ||
78 | #ifdef DEBUG | |
79 | const char *step_string_tbl[] = { | |
80 | "STEP_GET_SPD", | |
81 | "STEP_COMPUTE_DIMM_PARMS", | |
82 | "STEP_COMPUTE_COMMON_PARMS", | |
83 | "STEP_GATHER_OPTS", | |
84 | "STEP_ASSIGN_ADDRESSES", | |
85 | "STEP_COMPUTE_REGS", | |
86 | "STEP_PROGRAM_REGS", | |
87 | "STEP_ALL" | |
88 | }; | |
89 | ||
90 | const char * step_to_string(unsigned int step) { | |
91 | ||
92 | unsigned int s = __ilog2(step); | |
93 | ||
94 | if ((1 << s) != step) | |
95 | return step_string_tbl[7]; | |
96 | ||
97 | return step_string_tbl[s]; | |
98 | } | |
99 | #endif | |
100 | ||
101 | int step_assign_addresses(fsl_ddr_info_t *pinfo, | |
102 | unsigned int dbw_cap_adj[], | |
103 | unsigned int *memctl_interleaving, | |
104 | unsigned int *rank_interleaving) | |
105 | { | |
106 | int i, j; | |
107 | ||
108 | /* | |
109 | * If a reduced data width is requested, but the SPD | |
110 | * specifies a physically wider device, adjust the | |
111 | * computed dimm capacities accordingly before | |
112 | * assigning addresses. | |
113 | */ | |
114 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
115 | unsigned int found = 0; | |
116 | ||
117 | switch (pinfo->memctl_opts[i].data_bus_width) { | |
118 | case 2: | |
119 | /* 16-bit */ | |
120 | printf("can't handle 16-bit mode yet\n"); | |
121 | break; | |
122 | ||
123 | case 1: | |
124 | /* 32-bit */ | |
125 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
126 | unsigned int dw; | |
127 | dw = pinfo->dimm_params[i][j].data_width; | |
128 | if (pinfo->dimm_params[i][j].n_ranks | |
129 | && (dw == 72 || dw == 64)) { | |
130 | /* | |
131 | * FIXME: can't really do it | |
132 | * like this because this just | |
133 | * further reduces the memory | |
134 | */ | |
135 | found = 1; | |
136 | break; | |
137 | } | |
138 | } | |
139 | if (found) { | |
140 | dbw_cap_adj[i] = 1; | |
141 | } | |
142 | break; | |
143 | ||
144 | case 0: | |
145 | /* 64-bit */ | |
146 | break; | |
147 | ||
148 | default: | |
149 | printf("unexpected data bus width " | |
150 | "specified controller %u\n", i); | |
151 | return 1; | |
152 | } | |
153 | } | |
154 | ||
155 | /* | |
156 | * Check if all controllers are configured for memory | |
157 | * controller interleaving. | |
158 | */ | |
159 | j = 0; | |
160 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
161 | if (pinfo->memctl_opts[i].memctl_interleaving) { | |
162 | j++; | |
163 | } | |
164 | } | |
d9c147f3 | 165 | if (j == 2) |
58e5e9af | 166 | *memctl_interleaving = 1; |
c9ffd839 | 167 | |
58e5e9af KG |
168 | /* Check that all controllers are rank interleaving. */ |
169 | j = 0; | |
170 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
171 | if (pinfo->memctl_opts[i].ba_intlv_ctl) { | |
172 | j++; | |
173 | } | |
174 | } | |
d9c147f3 | 175 | if (j == 2) |
58e5e9af | 176 | *rank_interleaving = 1; |
c9ffd839 | 177 | |
58e5e9af | 178 | if (*memctl_interleaving) { |
e7563aff | 179 | unsigned long long addr, total_mem_per_ctlr = 0; |
58e5e9af KG |
180 | /* |
181 | * If interleaving between memory controllers, | |
182 | * make each controller start at a base address | |
183 | * of 0. | |
184 | * | |
185 | * Also, if bank interleaving (chip select | |
186 | * interleaving) is enabled on each memory | |
187 | * controller, CS0 needs to be programmed to | |
188 | * cover the entire memory range on that memory | |
189 | * controller | |
190 | * | |
191 | * Bank interleaving also implies that each | |
192 | * addressed chip select is identical in size. | |
193 | */ | |
194 | ||
195 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
196 | addr = 0; | |
e7563aff | 197 | pinfo->common_timing_params[i].base_address = 0ull; |
58e5e9af KG |
198 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { |
199 | unsigned long long cap | |
200 | = pinfo->dimm_params[i][j].capacity; | |
201 | ||
202 | pinfo->dimm_params[i][j].base_address = addr; | |
e7563aff | 203 | addr += cap >> dbw_cap_adj[i]; |
dbbbb3ab | 204 | total_mem_per_ctlr += cap >> dbw_cap_adj[i]; |
58e5e9af KG |
205 | } |
206 | } | |
dbbbb3ab | 207 | pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr; |
58e5e9af KG |
208 | } else { |
209 | /* | |
210 | * Simple linear assignment if memory | |
211 | * controllers are not interleaved. | |
212 | */ | |
e7563aff | 213 | unsigned long long cur_memsize = 0; |
58e5e9af | 214 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { |
e7563aff | 215 | u64 total_mem_per_ctlr = 0; |
58e5e9af | 216 | pinfo->common_timing_params[i].base_address = |
e7563aff | 217 | cur_memsize; |
58e5e9af KG |
218 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { |
219 | /* Compute DIMM base addresses. */ | |
220 | unsigned long long cap = | |
221 | pinfo->dimm_params[i][j].capacity; | |
58e5e9af | 222 | pinfo->dimm_params[i][j].base_address = |
e7563aff | 223 | cur_memsize; |
58e5e9af KG |
224 | cur_memsize += cap >> dbw_cap_adj[i]; |
225 | total_mem_per_ctlr += cap >> dbw_cap_adj[i]; | |
226 | } | |
227 | pinfo->common_timing_params[i].total_mem = | |
228 | total_mem_per_ctlr; | |
229 | } | |
230 | } | |
231 | ||
232 | return 0; | |
233 | } | |
234 | ||
e7563aff | 235 | unsigned long long |
58e5e9af KG |
236 | fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step) |
237 | { | |
238 | unsigned int i, j; | |
239 | unsigned int all_controllers_memctl_interleaving = 0; | |
240 | unsigned int all_controllers_rank_interleaving = 0; | |
e7563aff | 241 | unsigned long long total_mem = 0; |
58e5e9af KG |
242 | |
243 | fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; | |
244 | common_timing_params_t *timing_params = pinfo->common_timing_params; | |
245 | ||
246 | /* data bus width capacity adjust shift amount */ | |
247 | unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS]; | |
248 | ||
249 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
250 | dbw_capacity_adjust[i] = 0; | |
251 | } | |
252 | ||
253 | debug("starting at step %u (%s)\n", | |
254 | start_step, step_to_string(start_step)); | |
255 | ||
256 | switch (start_step) { | |
257 | case STEP_GET_SPD: | |
258 | /* STEP 1: Gather all DIMM SPD data */ | |
259 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
260 | fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i); | |
261 | } | |
262 | ||
263 | case STEP_COMPUTE_DIMM_PARMS: | |
264 | /* STEP 2: Compute DIMM parameters from SPD data */ | |
265 | ||
266 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
267 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
268 | unsigned int retval; | |
269 | generic_spd_eeprom_t *spd = | |
270 | &(pinfo->spd_installed_dimms[i][j]); | |
271 | dimm_params_t *pdimm = | |
f12e4549 | 272 | &(pinfo->dimm_params[i][j]); |
58e5e9af KG |
273 | |
274 | retval = compute_dimm_parameters(spd, pdimm, i); | |
275 | if (retval == 2) { | |
276 | printf("Error: compute_dimm_parameters" | |
277 | " non-zero returned FATAL value " | |
278 | "for memctl=%u dimm=%u\n", i, j); | |
279 | return 0; | |
280 | } | |
281 | if (retval) { | |
282 | debug("Warning: compute_dimm_parameters" | |
283 | " non-zero return value for memctl=%u " | |
284 | "dimm=%u\n", i, j); | |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | case STEP_COMPUTE_COMMON_PARMS: | |
290 | /* | |
291 | * STEP 3: Compute a common set of timing parameters | |
292 | * suitable for all of the DIMMs on each memory controller | |
293 | */ | |
294 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
295 | debug("Computing lowest common DIMM" | |
296 | " parameters for memctl=%u\n", i); | |
297 | compute_lowest_common_dimm_parameters( | |
298 | pinfo->dimm_params[i], | |
299 | &timing_params[i], | |
300 | CONFIG_DIMM_SLOTS_PER_CTLR); | |
301 | } | |
302 | ||
303 | case STEP_GATHER_OPTS: | |
304 | /* STEP 4: Gather configuration requirements from user */ | |
305 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
306 | debug("Reloading memory controller " | |
307 | "configuration options for memctl=%u\n", i); | |
308 | /* | |
309 | * This "reloads" the memory controller options | |
310 | * to defaults. If the user "edits" an option, | |
311 | * next_step points to the step after this, | |
312 | * which is currently STEP_ASSIGN_ADDRESSES. | |
313 | */ | |
314 | populate_memctl_options( | |
315 | timing_params[i].all_DIMMs_registered, | |
dfb49108 HW |
316 | &pinfo->memctl_opts[i], |
317 | pinfo->dimm_params[i], i); | |
58e5e9af KG |
318 | } |
319 | ||
320 | case STEP_ASSIGN_ADDRESSES: | |
321 | /* STEP 5: Assign addresses to chip selects */ | |
322 | step_assign_addresses(pinfo, | |
323 | dbw_capacity_adjust, | |
324 | &all_controllers_memctl_interleaving, | |
325 | &all_controllers_rank_interleaving); | |
326 | ||
327 | case STEP_COMPUTE_REGS: | |
328 | /* STEP 6: compute controller register values */ | |
329 | debug("FSL Memory ctrl cg register computation\n"); | |
330 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
331 | if (timing_params[i].ndimms_present == 0) { | |
332 | memset(&ddr_reg[i], 0, | |
333 | sizeof(fsl_ddr_cfg_regs_t)); | |
334 | continue; | |
335 | } | |
336 | ||
337 | compute_fsl_memctl_config_regs( | |
338 | &pinfo->memctl_opts[i], | |
339 | &ddr_reg[i], &timing_params[i], | |
340 | pinfo->dimm_params[i], | |
341 | dbw_capacity_adjust[i]); | |
342 | } | |
343 | ||
344 | default: | |
345 | break; | |
346 | } | |
347 | ||
348 | /* Compute the total amount of memory. */ | |
349 | ||
350 | /* | |
351 | * If bank interleaving but NOT memory controller interleaving | |
352 | * CS_BNDS describe the quantity of memory on each memory | |
353 | * controller, so the total is the sum across. | |
354 | */ | |
355 | if (!all_controllers_memctl_interleaving | |
356 | && all_controllers_rank_interleaving) { | |
357 | total_mem = 0; | |
358 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
359 | total_mem += timing_params[i].total_mem; | |
360 | } | |
361 | ||
362 | } else { | |
363 | /* | |
364 | * Compute the amount of memory available just by | |
365 | * looking for the highest valid CSn_BNDS value. | |
366 | * This allows us to also experiment with using | |
367 | * only CS0 when using dual-rank DIMMs. | |
368 | */ | |
369 | unsigned int max_end = 0; | |
370 | ||
371 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
372 | for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) { | |
373 | fsl_ddr_cfg_regs_t *reg = &ddr_reg[i]; | |
374 | if (reg->cs[j].config & 0x80000000) { | |
375 | unsigned int end; | |
376 | end = reg->cs[j].bnds & 0xFFF; | |
377 | if (end > max_end) { | |
378 | max_end = end; | |
379 | } | |
380 | } | |
381 | } | |
382 | } | |
383 | ||
58e5e9af KG |
384 | total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
385 | | 0xFFFFFFULL); | |
386 | } | |
387 | ||
388 | return total_mem; | |
389 | } | |
390 | ||
391 | /* | |
392 | * fsl_ddr_sdram() -- this is the main function to be called by | |
393 | * initdram() in the board file. | |
394 | * | |
395 | * It returns amount of memory configured in bytes. | |
396 | */ | |
397 | phys_size_t fsl_ddr_sdram(void) | |
398 | { | |
399 | unsigned int i; | |
400 | unsigned int memctl_interleaved; | |
e7563aff | 401 | unsigned long long total_memory; |
58e5e9af KG |
402 | fsl_ddr_info_t info; |
403 | ||
404 | /* Reset info structure. */ | |
405 | memset(&info, 0, sizeof(fsl_ddr_info_t)); | |
406 | ||
407 | /* Compute it once normally. */ | |
408 | total_memory = fsl_ddr_compute(&info, STEP_GET_SPD); | |
409 | ||
410 | /* Check for memory controller interleaving. */ | |
411 | memctl_interleaved = 0; | |
412 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
413 | memctl_interleaved += | |
414 | info.memctl_opts[i].memctl_interleaving; | |
415 | } | |
416 | ||
417 | if (memctl_interleaved) { | |
418 | if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) { | |
419 | debug("memctl interleaving\n"); | |
420 | /* | |
421 | * Change the meaning of memctl_interleaved | |
422 | * to be "boolean". | |
423 | */ | |
424 | memctl_interleaved = 1; | |
425 | } else { | |
7008d26a | 426 | printf("Warning: memctl interleaving not " |
58e5e9af | 427 | "properly configured on all controllers\n"); |
7008d26a ES |
428 | memctl_interleaved = 0; |
429 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) | |
430 | info.memctl_opts[i].memctl_interleaving = 0; | |
431 | debug("Recomputing with memctl_interleaving off.\n"); | |
432 | total_memory = fsl_ddr_compute(&info, | |
433 | STEP_ASSIGN_ADDRESSES); | |
58e5e9af KG |
434 | } |
435 | } | |
436 | ||
437 | /* Program configuration registers. */ | |
438 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
439 | debug("Programming controller %u\n", i); | |
440 | if (info.common_timing_params[i].ndimms_present == 0) { | |
441 | debug("No dimms present on controller %u; " | |
442 | "skipping programming\n", i); | |
443 | continue; | |
444 | } | |
445 | ||
446 | fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i); | |
447 | } | |
448 | ||
449 | if (memctl_interleaved) { | |
450 | const unsigned int ctrl_num = 0; | |
451 | ||
452 | /* Only set LAWBAR1 if memory controller interleaving is on. */ | |
453 | fsl_ddr_set_lawbar(&info.common_timing_params[0], | |
454 | memctl_interleaved, ctrl_num); | |
455 | } else { | |
456 | /* | |
457 | * Memory controller interleaving is NOT on; | |
458 | * set each lawbar individually. | |
459 | */ | |
460 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
461 | fsl_ddr_set_lawbar(&info.common_timing_params[i], | |
462 | 0, i); | |
463 | } | |
464 | } | |
465 | ||
e7563aff KG |
466 | debug("total_memory = %llu\n", total_memory); |
467 | ||
468 | #if !defined(CONFIG_PHYS_64BIT) | |
469 | /* Check for 4G or more. Bad. */ | |
470 | if (total_memory >= (1ull << 32)) { | |
471 | printf("Detected %lld MB of memory\n", total_memory >> 20); | |
472 | printf("This U-Boot only supports < 4G of DDR\n"); | |
473 | printf("You could rebuild it with CONFIG_PHYS_64BIT\n"); | |
474 | total_memory = CONFIG_MAX_MEM_MAPPED; | |
475 | } | |
476 | #endif | |
58e5e9af KG |
477 | |
478 | return total_memory; | |
479 | } |