]>
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 | * -------------------------------|-----------|-----------|----------------- | |
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 | |
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 | |
58 | * | per memory controller supported | |
59 | * --------------------------------|----------------------------------------- | |
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 | |
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 | * | |
72 | * Name of field | documentation name | this code | |
73 | * -----------------------------|-----------------------|------------------ | |
74 | * DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving | |
75 | * | interleaving | |
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 | } | |
165 | if (j == 2) { | |
166 | *memctl_interleaving = 1; | |
167 | } | |
168 | ||
169 | /* Check that all controllers are rank interleaving. */ | |
170 | j = 0; | |
171 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
172 | if (pinfo->memctl_opts[i].ba_intlv_ctl) { | |
173 | j++; | |
174 | } | |
175 | } | |
176 | if (j == 2) { | |
177 | *rank_interleaving = 1; | |
178 | } | |
179 | ||
180 | if (*memctl_interleaving) { | |
181 | phys_addr_t addr; | |
182 | ||
183 | /* | |
184 | * If interleaving between memory controllers, | |
185 | * make each controller start at a base address | |
186 | * of 0. | |
187 | * | |
188 | * Also, if bank interleaving (chip select | |
189 | * interleaving) is enabled on each memory | |
190 | * controller, CS0 needs to be programmed to | |
191 | * cover the entire memory range on that memory | |
192 | * controller | |
193 | * | |
194 | * Bank interleaving also implies that each | |
195 | * addressed chip select is identical in size. | |
196 | */ | |
197 | ||
198 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
199 | addr = 0; | |
200 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
201 | unsigned long long cap | |
202 | = pinfo->dimm_params[i][j].capacity; | |
203 | ||
204 | pinfo->dimm_params[i][j].base_address = addr; | |
205 | addr += (phys_addr_t)(cap >> dbw_cap_adj[i]); | |
206 | } | |
207 | } | |
208 | } else { | |
209 | /* | |
210 | * Simple linear assignment if memory | |
211 | * controllers are not interleaved. | |
212 | */ | |
213 | phys_size_t cur_memsize = 0; | |
214 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
215 | phys_size_t total_mem_per_ctlr = 0; | |
216 | pinfo->common_timing_params[i].base_address = | |
217 | (phys_addr_t)cur_memsize; | |
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; | |
222 | ||
223 | pinfo->dimm_params[i][j].base_address = | |
224 | (phys_addr_t)cur_memsize; | |
225 | cur_memsize += cap >> dbw_cap_adj[i]; | |
226 | total_mem_per_ctlr += cap >> dbw_cap_adj[i]; | |
227 | } | |
228 | pinfo->common_timing_params[i].total_mem = | |
229 | total_mem_per_ctlr; | |
230 | } | |
231 | } | |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
236 | phys_size_t | |
237 | fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step) | |
238 | { | |
239 | unsigned int i, j; | |
240 | unsigned int all_controllers_memctl_interleaving = 0; | |
241 | unsigned int all_controllers_rank_interleaving = 0; | |
242 | phys_size_t total_mem = 0; | |
243 | ||
244 | fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; | |
245 | common_timing_params_t *timing_params = pinfo->common_timing_params; | |
246 | ||
247 | /* data bus width capacity adjust shift amount */ | |
248 | unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS]; | |
249 | ||
250 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
251 | dbw_capacity_adjust[i] = 0; | |
252 | } | |
253 | ||
254 | debug("starting at step %u (%s)\n", | |
255 | start_step, step_to_string(start_step)); | |
256 | ||
257 | switch (start_step) { | |
258 | case STEP_GET_SPD: | |
259 | /* STEP 1: Gather all DIMM SPD data */ | |
260 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
261 | fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i); | |
262 | } | |
263 | ||
264 | case STEP_COMPUTE_DIMM_PARMS: | |
265 | /* STEP 2: Compute DIMM parameters from SPD data */ | |
266 | ||
267 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
268 | for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { | |
269 | unsigned int retval; | |
270 | generic_spd_eeprom_t *spd = | |
271 | &(pinfo->spd_installed_dimms[i][j]); | |
272 | dimm_params_t *pdimm = | |
273 | &(pinfo->dimm_params[i][j]); | |
274 | ||
275 | retval = compute_dimm_parameters(spd, pdimm, i); | |
276 | if (retval == 2) { | |
277 | printf("Error: compute_dimm_parameters" | |
278 | " non-zero returned FATAL value " | |
279 | "for memctl=%u dimm=%u\n", i, j); | |
280 | return 0; | |
281 | } | |
282 | if (retval) { | |
283 | debug("Warning: compute_dimm_parameters" | |
284 | " non-zero return value for memctl=%u " | |
285 | "dimm=%u\n", i, j); | |
286 | } | |
287 | } | |
288 | } | |
289 | ||
290 | case STEP_COMPUTE_COMMON_PARMS: | |
291 | /* | |
292 | * STEP 3: Compute a common set of timing parameters | |
293 | * suitable for all of the DIMMs on each memory controller | |
294 | */ | |
295 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
296 | debug("Computing lowest common DIMM" | |
297 | " parameters for memctl=%u\n", i); | |
298 | compute_lowest_common_dimm_parameters( | |
299 | pinfo->dimm_params[i], | |
300 | &timing_params[i], | |
301 | CONFIG_DIMM_SLOTS_PER_CTLR); | |
302 | } | |
303 | ||
304 | case STEP_GATHER_OPTS: | |
305 | /* STEP 4: Gather configuration requirements from user */ | |
306 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
307 | debug("Reloading memory controller " | |
308 | "configuration options for memctl=%u\n", i); | |
309 | /* | |
310 | * This "reloads" the memory controller options | |
311 | * to defaults. If the user "edits" an option, | |
312 | * next_step points to the step after this, | |
313 | * which is currently STEP_ASSIGN_ADDRESSES. | |
314 | */ | |
315 | populate_memctl_options( | |
316 | timing_params[i].all_DIMMs_registered, | |
317 | &pinfo->memctl_opts[i], i); | |
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 | ||
384 | #if !defined(CONFIG_PHYS_64BIT) | |
385 | /* Check for 4G or more with a 32-bit phys_addr_t. Bad. */ | |
386 | if (max_end >= 0xff) { | |
387 | printf("This U-Boot only supports < 4G of DDR\n"); | |
388 | printf("You could rebuild it with CONFIG_PHYS_64BIT\n"); | |
389 | return 0; /* Ensure DDR setup failure. */ | |
390 | } | |
391 | #endif | |
392 | ||
393 | total_mem = 1 + (((unsigned long long)max_end << 24ULL) | |
394 | | 0xFFFFFFULL); | |
395 | } | |
396 | ||
397 | return total_mem; | |
398 | } | |
399 | ||
400 | /* | |
401 | * fsl_ddr_sdram() -- this is the main function to be called by | |
402 | * initdram() in the board file. | |
403 | * | |
404 | * It returns amount of memory configured in bytes. | |
405 | */ | |
406 | phys_size_t fsl_ddr_sdram(void) | |
407 | { | |
408 | unsigned int i; | |
409 | unsigned int memctl_interleaved; | |
410 | phys_size_t total_memory; | |
411 | fsl_ddr_info_t info; | |
412 | ||
413 | /* Reset info structure. */ | |
414 | memset(&info, 0, sizeof(fsl_ddr_info_t)); | |
415 | ||
416 | /* Compute it once normally. */ | |
417 | total_memory = fsl_ddr_compute(&info, STEP_GET_SPD); | |
418 | ||
419 | /* Check for memory controller interleaving. */ | |
420 | memctl_interleaved = 0; | |
421 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
422 | memctl_interleaved += | |
423 | info.memctl_opts[i].memctl_interleaving; | |
424 | } | |
425 | ||
426 | if (memctl_interleaved) { | |
427 | if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) { | |
428 | debug("memctl interleaving\n"); | |
429 | /* | |
430 | * Change the meaning of memctl_interleaved | |
431 | * to be "boolean". | |
432 | */ | |
433 | memctl_interleaved = 1; | |
434 | } else { | |
435 | printf("Error: memctl interleaving not " | |
436 | "properly configured on all controllers\n"); | |
437 | while (1); | |
438 | } | |
439 | } | |
440 | ||
441 | /* Program configuration registers. */ | |
442 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
443 | debug("Programming controller %u\n", i); | |
444 | if (info.common_timing_params[i].ndimms_present == 0) { | |
445 | debug("No dimms present on controller %u; " | |
446 | "skipping programming\n", i); | |
447 | continue; | |
448 | } | |
449 | ||
450 | fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i); | |
451 | } | |
452 | ||
453 | if (memctl_interleaved) { | |
454 | const unsigned int ctrl_num = 0; | |
455 | ||
456 | /* Only set LAWBAR1 if memory controller interleaving is on. */ | |
457 | fsl_ddr_set_lawbar(&info.common_timing_params[0], | |
458 | memctl_interleaved, ctrl_num); | |
459 | } else { | |
460 | /* | |
461 | * Memory controller interleaving is NOT on; | |
462 | * set each lawbar individually. | |
463 | */ | |
464 | for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { | |
465 | fsl_ddr_set_lawbar(&info.common_timing_params[i], | |
466 | 0, i); | |
467 | } | |
468 | } | |
469 | ||
470 | debug("total_memory = %llu\n", (u64)total_memory); | |
471 | ||
472 | return total_memory; | |
473 | } |