]> git.sur5r.net Git - u-boot/blob - arch/powerpc/cpu/mpc8xxx/ddr/options.c
powerpc/8xxx: Add hwconfig APIs to address early parsing used by DDR init
[u-boot] / arch / powerpc / cpu / mpc8xxx / ddr / options.c
1 /*
2  * Copyright 2008, 2010-2011 Freescale Semiconductor, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  */
9
10 #include <common.h>
11 #include <hwconfig.h>
12 #include <asm/fsl_ddr_sdram.h>
13
14 #include "ddr.h"
15
16 /*
17  * Use our own stack based buffer before relocation to allow accessing longer
18  * hwconfig strings that might be in the environment before we've relocated.
19  * This is pretty fragile on both the use of stack and if the buffer is big
20  * enough. However we will get a warning from getenv_f for the later.
21  */
22 #define HWCONFIG_BUFFER_SIZE    128
23
24 /* Board-specific functions defined in each board's ddr.c */
25 extern void fsl_ddr_board_options(memctl_options_t *popts,
26                 dimm_params_t *pdimm,
27                 unsigned int ctrl_num);
28
29 unsigned int populate_memctl_options(int all_DIMMs_registered,
30                         memctl_options_t *popts,
31                         dimm_params_t *pdimm,
32                         unsigned int ctrl_num)
33 {
34         unsigned int i;
35         char buffer[HWCONFIG_BUFFER_SIZE];
36         char *buf = NULL;
37
38         /*
39          * Extract hwconfig from environment since we have not properly setup
40          * the environment but need it for ddr config params
41          */
42         if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
43                 buf = buffer;
44
45         /* Chip select options. */
46
47         /* Pick chip-select local options. */
48         for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
49                 /* If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. */
50
51                 /* only for single CS? */
52                 popts->cs_local_opts[i].odt_rd_cfg = 0;
53
54                 popts->cs_local_opts[i].odt_wr_cfg = 1;
55                 popts->cs_local_opts[i].auto_precharge = 0;
56         }
57
58         /* Pick interleaving mode. */
59
60         /*
61          * 0 = no interleaving
62          * 1 = interleaving between 2 controllers
63          */
64         popts->memctl_interleaving = 0;
65
66         /*
67          * 0 = cacheline
68          * 1 = page
69          * 2 = (logical) bank
70          * 3 = superbank (only if CS interleaving is enabled)
71          */
72         popts->memctl_interleaving_mode = 0;
73
74         /*
75          * 0: cacheline: bit 30 of the 36-bit physical addr selects the memctl
76          * 1: page:      bit to the left of the column bits selects the memctl
77          * 2: bank:      bit to the left of the bank bits selects the memctl
78          * 3: superbank: bit to the left of the chip select selects the memctl
79          *
80          * NOTE: ba_intlv (rank interleaving) is independent of memory
81          * controller interleaving; it is only within a memory controller.
82          * Must use superbank interleaving if rank interleaving is used and
83          * memory controller interleaving is enabled.
84          */
85
86         /*
87          * 0 = no
88          * 0x40 = CS0,CS1
89          * 0x20 = CS2,CS3
90          * 0x60 = CS0,CS1 + CS2,CS3
91          * 0x04 = CS0,CS1,CS2,CS3
92          */
93         popts->ba_intlv_ctl = 0;
94
95         /* Memory Organization Parameters */
96         popts->registered_dimm_en = all_DIMMs_registered;
97
98         /* Operational Mode Paramters */
99
100         /* Pick ECC modes */
101 #ifdef CONFIG_DDR_ECC
102         popts->ECC_mode = 1;              /* 0 = disabled, 1 = enabled */
103 #else
104         popts->ECC_mode = 0;              /* 0 = disabled, 1 = enabled */
105 #endif
106         popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
107
108         /*
109          * Choose DQS config
110          * 0 for DDR1
111          * 1 for DDR2
112          */
113 #if defined(CONFIG_FSL_DDR1)
114         popts->DQS_config = 0;
115 #elif defined(CONFIG_FSL_DDR2) || defined(CONFIG_FSL_DDR3)
116         popts->DQS_config = 1;
117 #endif
118
119         /* Choose self-refresh during sleep. */
120         popts->self_refresh_in_sleep = 1;
121
122         /* Choose dynamic power management mode. */
123         popts->dynamic_power = 0;
124
125         /* 0 = 64-bit, 1 = 32-bit, 2 = 16-bit */
126         popts->data_bus_width = 0;
127
128         /* Choose burst length. */
129 #if defined(CONFIG_FSL_DDR3)
130 #if defined(CONFIG_E500MC)
131         popts->OTF_burst_chop_en = 0;   /* on-the-fly burst chop disable */
132         popts->burst_length = DDR_BL8;  /* Fixed 8-beat burst len */
133 #else
134         popts->OTF_burst_chop_en = 1;   /* on-the-fly burst chop */
135         popts->burst_length = DDR_OTF;  /* on-the-fly BC4 and BL8 */
136 #endif
137 #else
138         popts->burst_length = DDR_BL4;  /* has to be 4 for DDR2 */
139 #endif
140
141         /* Choose ddr controller address mirror mode */
142 #if defined(CONFIG_FSL_DDR3)
143         popts->mirrored_dimm = pdimm[0].mirrored_dimm;
144 #endif
145
146         /* Global Timing Parameters. */
147         debug("mclk_ps = %u ps\n", get_memory_clk_period_ps());
148
149         /* Pick a caslat override. */
150         popts->cas_latency_override = 0;
151         popts->cas_latency_override_value = 3;
152         if (popts->cas_latency_override) {
153                 debug("using caslat override value = %u\n",
154                        popts->cas_latency_override_value);
155         }
156
157         /* Decide whether to use the computed derated latency */
158         popts->use_derated_caslat = 0;
159
160         /* Choose an additive latency. */
161         popts->additive_latency_override = 0;
162         popts->additive_latency_override_value = 3;
163         if (popts->additive_latency_override) {
164                 debug("using additive latency override value = %u\n",
165                        popts->additive_latency_override_value);
166         }
167
168         /*
169          * 2T_EN setting
170          *
171          * Factors to consider for 2T_EN:
172          *      - number of DIMMs installed
173          *      - number of components, number of active ranks
174          *      - how much time you want to spend playing around
175          */
176         popts->twoT_en = 0;
177         popts->threeT_en = 0;
178
179         /*
180          * BSTTOPRE precharge interval
181          *
182          * Set this to 0 for global auto precharge
183          *
184          * FIXME: Should this be configured in picoseconds?
185          * Why it should be in ps:  better understanding of this
186          * relative to actual DRAM timing parameters such as tRAS.
187          * e.g. tRAS(min) = 40 ns
188          */
189         popts->bstopre = 0x100;
190
191         /* Minimum CKE pulse width -- tCKE(MIN) */
192         popts->tCKE_clock_pulse_width_ps
193                 = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
194
195         /*
196          * Window for four activates -- tFAW
197          *
198          * FIXME: UM: applies only to DDR2/DDR3 with eight logical banks only
199          * FIXME: varies depending upon number of column addresses or data
200          * FIXME: width, was considering looking at pdimm->primary_sdram_width
201          */
202 #if defined(CONFIG_FSL_DDR1)
203         popts->tFAW_window_four_activates_ps = mclk_to_picos(1);
204
205 #elif defined(CONFIG_FSL_DDR2)
206         /*
207          * x4/x8;  some datasheets have 35000
208          * x16 wide columns only?  Use 50000?
209          */
210         popts->tFAW_window_four_activates_ps = 37500;
211
212 #elif defined(CONFIG_FSL_DDR3)
213         popts->tFAW_window_four_activates_ps = pdimm[0].tFAW_ps;
214 #endif
215         popts->zq_en = 0;
216         popts->wrlvl_en = 0;
217 #if defined(CONFIG_FSL_DDR3)
218         /*
219          * due to ddr3 dimm is fly-by topology
220          * we suggest to enable write leveling to
221          * meet the tQDSS under different loading.
222          */
223         popts->wrlvl_en = 1;
224         popts->zq_en = 1;
225         popts->wrlvl_override = 0;
226 #endif
227
228         /*
229          * Check interleaving configuration from environment.
230          * Please refer to doc/README.fsl-ddr for the detail.
231          *
232          * If memory controller interleaving is enabled, then the data
233          * bus widths must be programmed identically for all memory controllers.
234          *
235          * XXX: Attempt to set all controllers to the same chip select
236          * interleaving mode. It will do a best effort to get the
237          * requested ranks interleaved together such that the result
238          * should be a subset of the requested configuration.
239          */
240 #if (CONFIG_NUM_DDR_CONTROLLERS > 1)
241         if (hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) {
242                 if (pdimm[0].n_ranks == 0) {
243                         printf("There is no rank on CS0 for controller %d. Because only"
244                                 " rank on CS0 and ranks chip-select interleaved with CS0"
245                                 " are controller interleaved, force non memory "
246                                 "controller interleaving\n", ctrl_num);
247                         popts->memctl_interleaving = 0;
248                 } else {
249                         popts->memctl_interleaving = 1;
250                         /*
251                          * test null first. if CONFIG_HWCONFIG is not defined
252                          * hwconfig_arg_cmp returns non-zero
253                          */
254                         if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
255                                                     "null", buf)) {
256                                 popts->memctl_interleaving = 0;
257                                 debug("memory controller interleaving disabled.\n");
258                         } else if (hwconfig_subarg_cmp_f("fsl_ddr",
259                                                          "ctlr_intlv",
260                                                          "cacheline", buf))
261                                 popts->memctl_interleaving_mode =
262                                         FSL_DDR_CACHE_LINE_INTERLEAVING;
263                         else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
264                                                        "page", buf))
265                                 popts->memctl_interleaving_mode =
266                                         FSL_DDR_PAGE_INTERLEAVING;
267                         else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
268                                                        "bank", buf))
269                                 popts->memctl_interleaving_mode =
270                                         FSL_DDR_BANK_INTERLEAVING;
271                         else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
272                                                        "superbank", buf))
273                                 popts->memctl_interleaving_mode =
274                                         FSL_DDR_SUPERBANK_INTERLEAVING;
275                         else {
276                                 popts->memctl_interleaving = 0;
277                                 printf("hwconfig has unrecognized parameter for ctlr_intlv.\n");
278                         }
279                 }
280         }
281 #endif
282         if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) &&
283                 (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
284                 /* test null first. if CONFIG_HWCONFIG is not defined,
285                  * hwconfig_subarg_cmp_f returns non-zero */
286                 if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
287                                             "null", buf))
288                         debug("bank interleaving disabled.\n");
289                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
290                                                  "cs0_cs1", buf))
291                         popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
292                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
293                                                  "cs2_cs3", buf))
294                         popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
295                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
296                                                  "cs0_cs1_and_cs2_cs3", buf))
297                         popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
298                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
299                                                  "cs0_cs1_cs2_cs3", buf))
300                         popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
301                 else
302                         printf("hwconfig has unrecognized parameter for bank_intlv.\n");
303                 switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
304                 case FSL_DDR_CS0_CS1_CS2_CS3:
305 #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
306                         if (pdimm[0].n_ranks < 4) {
307                                 popts->ba_intlv_ctl = 0;
308                                 printf("Not enough bank(chip-select) for "
309                                         "CS0+CS1+CS2+CS3 on controller %d, "
310                                         "force non-interleaving!\n", ctrl_num);
311                         }
312 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
313                         if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) {
314                                 popts->ba_intlv_ctl = 0;
315                                 printf("Not enough bank(chip-select) for "
316                                         "CS0+CS1+CS2+CS3 on controller %d, "
317                                         "force non-interleaving!\n", ctrl_num);
318                         }
319                         if (pdimm[0].capacity != pdimm[1].capacity) {
320                                 popts->ba_intlv_ctl = 0;
321                                 printf("Not identical DIMM size for "
322                                         "CS0+CS1+CS2+CS3 on controller %d, "
323                                         "force non-interleaving!\n", ctrl_num);
324                         }
325 #endif
326                         break;
327                 case FSL_DDR_CS0_CS1:
328                         if (pdimm[0].n_ranks < 2) {
329                                 popts->ba_intlv_ctl = 0;
330                                 printf("Not enough bank(chip-select) for "
331                                         "CS0+CS1 on controller %d, "
332                                         "force non-interleaving!\n", ctrl_num);
333                         }
334                         break;
335                 case FSL_DDR_CS2_CS3:
336 #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
337                         if (pdimm[0].n_ranks < 4) {
338                                 popts->ba_intlv_ctl = 0;
339                                 printf("Not enough bank(chip-select) for CS2+CS3 "
340                                         "on controller %d, force non-interleaving!\n", ctrl_num);
341                         }
342 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
343                         if (pdimm[1].n_ranks < 2) {
344                                 popts->ba_intlv_ctl = 0;
345                                 printf("Not enough bank(chip-select) for CS2+CS3 "
346                                         "on controller %d, force non-interleaving!\n", ctrl_num);
347                         }
348 #endif
349                         break;
350                 case FSL_DDR_CS0_CS1_AND_CS2_CS3:
351 #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
352                         if (pdimm[0].n_ranks < 4) {
353                                 popts->ba_intlv_ctl = 0;
354                                 printf("Not enough bank(CS) for CS0+CS1 and "
355                                         "CS2+CS3 on controller %d, "
356                                         "force non-interleaving!\n", ctrl_num);
357                         }
358 #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
359                         if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) {
360                                 popts->ba_intlv_ctl = 0;
361                                 printf("Not enough bank(CS) for CS0+CS1 and "
362                                         "CS2+CS3 on controller %d, "
363                                         "force non-interleaving!\n", ctrl_num);
364                         }
365 #endif
366                         break;
367                 default:
368                         popts->ba_intlv_ctl = 0;
369                         break;
370                 }
371         }
372
373         if (hwconfig_sub_f("fsl_ddr", "addr_hash", buf)) {
374                 if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash", "null", buf))
375                         popts->addr_hash = 0;
376                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash",
377                                                "true", buf))
378                         popts->addr_hash = 1;
379         }
380
381         if (pdimm[0].n_ranks == 4)
382                 popts->quad_rank_present = 1;
383
384         fsl_ddr_board_options(popts, pdimm, ctrl_num);
385
386         return 0;
387 }
388
389 void check_interleaving_options(fsl_ddr_info_t *pinfo)
390 {
391         int i, j, check_n_ranks, intlv_fixed = 0;
392         unsigned long long check_rank_density;
393         /*
394          * Check if all controllers are configured for memory
395          * controller interleaving. Identical dimms are recommended. At least
396          * the size should be checked.
397          */
398         j = 0;
399         check_n_ranks = pinfo->dimm_params[0][0].n_ranks;
400         check_rank_density = pinfo->dimm_params[0][0].rank_density;
401         for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
402                 if ((pinfo->memctl_opts[i].memctl_interleaving) && \
403                     (check_rank_density == pinfo->dimm_params[i][0].rank_density) && \
404                     (check_n_ranks == pinfo->dimm_params[i][0].n_ranks)) {
405                         j++;
406                 }
407         }
408         if (j != CONFIG_NUM_DDR_CONTROLLERS) {
409                 for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
410                         if (pinfo->memctl_opts[i].memctl_interleaving) {
411                                 pinfo->memctl_opts[i].memctl_interleaving = 0;
412                                 intlv_fixed = 1;
413                         }
414                 if (intlv_fixed)
415                         printf("Not all DIMMs are identical in size. "
416                                 "Memory controller interleaving disabled.\n");
417         }
418 }
419
420 int fsl_use_spd(void)
421 {
422         int use_spd = 0;
423
424 #ifdef CONFIG_DDR_SPD
425         char buffer[HWCONFIG_BUFFER_SIZE];
426         char *buf = NULL;
427
428         /*
429          * Extract hwconfig from environment since we have not properly setup
430          * the environment but need it for ddr config params
431          */
432         if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
433                 buf = buffer;
434
435         /* if hwconfig is not enabled, or "sdram" is not defined, use spd */
436         if (hwconfig_sub_f("fsl_ddr", "sdram", buf)) {
437                 if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram", "spd", buf))
438                         use_spd = 1;
439                 else if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram",
440                                                "fixed", buf))
441                         use_spd = 0;
442                 else
443                         use_spd = 1;
444         } else
445                 use_spd = 1;
446 #endif
447
448         return use_spd;
449 }