]>
Commit | Line | Data |
---|---|---|
075d0b81 | 1 | /* |
a47a12be | 2 | * arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c |
075d0b81 AG |
3 | * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a |
4 | * DDR2 controller (non Denali Core). Those currently are: | |
5 | * | |
6 | * 405: 405EX | |
7 | * 440/460: 440SP/440SPe/460EX/460GT/460SX | |
8 | * | |
9 | * (C) Copyright 2008 Applied Micro Circuits Corporation | |
10 | * Adam Graham <agraham@amcc.com> | |
11 | * | |
12 | * (C) Copyright 2007-2008 | |
13 | * Stefan Roese, DENX Software Engineering, sr@denx.de. | |
14 | * | |
15 | * COPYRIGHT AMCC CORPORATION 2004 | |
16 | * | |
17 | * See file CREDITS for list of people who contributed to this | |
18 | * project. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or | |
21 | * modify it under the terms of the GNU General Public License as | |
22 | * published by the Free Software Foundation; either version 2 of | |
23 | * the License, or (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
33 | * MA 02111-1307 USA | |
34 | * | |
35 | */ | |
36 | ||
37 | /* define DEBUG for debugging output (obviously ;-)) */ | |
38 | #undef DEBUG | |
39 | ||
40 | #include <common.h> | |
b36df561 | 41 | #include <asm/ppc4xx.h> |
075d0b81 AG |
42 | #include <asm/io.h> |
43 | #include <asm/processor.h> | |
44 | ||
fb95169e SR |
45 | #include "ecc.h" |
46 | ||
075d0b81 AG |
47 | /* |
48 | * Only compile the DDR auto-calibration code for NOR boot and | |
49 | * not for NAND boot (NAND SPL and NAND U-Boot - NUB) | |
50 | */ | |
51 | #if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) | |
52 | ||
53 | #define MAXBXCF 4 | |
54 | #define SDRAM_RXBAS_SHIFT_1M 20 | |
55 | ||
6d0f6bcf | 56 | #if defined(CONFIG_SYS_DECREMENT_PATTERNS) |
075d0b81 AG |
57 | #define NUMMEMTESTS 24 |
58 | #else | |
59 | #define NUMMEMTESTS 8 | |
6d0f6bcf | 60 | #endif /* CONFIG_SYS_DECREMENT_PATTERNS */ |
075d0b81 AG |
61 | #define NUMLOOPS 1 /* configure as you deem approporiate */ |
62 | #define NUMMEMWORDS 16 | |
63 | ||
c645012a AG |
64 | #define SDRAM_RDCC_RDSS_VAL(n) SDRAM_RDCC_RDSS_DECODE(ddr_rdss_opt(n)) |
65 | ||
075d0b81 AG |
66 | /* Private Structure Definitions */ |
67 | ||
68 | struct autocal_regs { | |
69 | u32 rffd; | |
70 | u32 rqfd; | |
71 | }; | |
72 | ||
73 | struct ddrautocal { | |
74 | u32 rffd; | |
75 | u32 rffd_min; | |
76 | u32 rffd_max; | |
77 | u32 rffd_size; | |
78 | u32 rqfd; | |
79 | u32 rqfd_size; | |
80 | u32 rdcc; | |
81 | u32 flags; | |
82 | }; | |
83 | ||
075d0b81 AG |
84 | struct sdram_timing_clks { |
85 | u32 wrdtr; | |
86 | u32 clktr; | |
87 | u32 rdcc; | |
88 | u32 flags; | |
89 | }; | |
90 | ||
91 | struct autocal_clks { | |
92 | struct sdram_timing_clks clocks; | |
93 | struct ddrautocal autocal; | |
94 | }; | |
95 | ||
96 | /*--------------------------------------------------------------------------+ | |
97 | * Prototypes | |
98 | *--------------------------------------------------------------------------*/ | |
99 | #if defined(CONFIG_PPC4xx_DDR_METHOD_A) | |
100 | static u32 DQS_calibration_methodA(struct ddrautocal *); | |
101 | static u32 program_DQS_calibration_methodA(struct ddrautocal *); | |
102 | #else | |
103 | static u32 DQS_calibration_methodB(struct ddrautocal *); | |
104 | static u32 program_DQS_calibration_methodB(struct ddrautocal *); | |
105 | #endif | |
106 | static int short_mem_test(u32 *); | |
107 | ||
108 | /* | |
109 | * To provide an interface for board specific config values in this common | |
110 | * DDR setup code, we implement he "weak" default functions here. They return | |
111 | * the default value back to the caller. | |
112 | * | |
113 | * Please see include/configs/yucca.h for an example fora board specific | |
114 | * implementation. | |
115 | */ | |
116 | ||
117 | #if !defined(CONFIG_SPD_EEPROM) | |
118 | u32 __ddr_wrdtr(u32 default_val) | |
119 | { | |
120 | return default_val; | |
121 | } | |
122 | u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr"))); | |
123 | ||
124 | u32 __ddr_clktr(u32 default_val) | |
125 | { | |
126 | return default_val; | |
127 | } | |
128 | u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr"))); | |
129 | ||
130 | /* | |
131 | * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed | |
132 | */ | |
133 | void __spd_ddr_init_hang(void) | |
134 | { | |
135 | hang(); | |
136 | } | |
137 | void | |
138 | spd_ddr_init_hang(void) __attribute__((weak, alias("__spd_ddr_init_hang"))); | |
139 | #endif /* defined(CONFIG_SPD_EEPROM) */ | |
140 | ||
066003b2 | 141 | struct sdram_timing *__ddr_scan_option(struct sdram_timing *default_val) |
075d0b81 AG |
142 | { |
143 | return default_val; | |
144 | } | |
066003b2 SR |
145 | struct sdram_timing *ddr_scan_option(struct sdram_timing *) |
146 | __attribute__((weak, alias("__ddr_scan_option"))); | |
075d0b81 | 147 | |
c645012a AG |
148 | u32 __ddr_rdss_opt(u32 default_val) |
149 | { | |
150 | return default_val; | |
151 | } | |
152 | u32 ddr_rdss_opt(ulong) __attribute__((weak, alias("__ddr_rdss_opt"))); | |
153 | ||
154 | ||
075d0b81 AG |
155 | static u32 *get_membase(int bxcr_num) |
156 | { | |
157 | ulong bxcf; | |
158 | u32 *membase; | |
159 | ||
160 | #if defined(SDRAM_R0BAS) | |
161 | /* BAS from Memory Queue rank reg. */ | |
162 | membase = | |
163 | (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num))); | |
164 | bxcf = 0; /* just to satisfy the compiler */ | |
165 | #else | |
166 | /* BAS from SDRAM_MBxCF mem rank reg. */ | |
167 | mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); | |
168 | membase = (u32 *)((bxcf & 0xfff80000) << 3); | |
169 | #endif | |
170 | ||
171 | return membase; | |
172 | } | |
173 | ||
174 | static inline void ecc_clear_status_reg(void) | |
175 | { | |
fb95169e | 176 | mtsdram(SDRAM_ECCES, 0xffffffff); |
075d0b81 AG |
177 | #if defined(SDRAM_R0BAS) |
178 | mtdcr(SDRAM_ERRSTATLL, 0xffffffff); | |
179 | #endif | |
180 | } | |
181 | ||
f8a00dea AG |
182 | /* |
183 | * Reset and relock memory DLL after SDRAM_CLKTR change | |
184 | */ | |
185 | static inline void relock_memory_DLL(void) | |
186 | { | |
187 | u32 reg; | |
188 | ||
189 | mtsdram(SDRAM_MCOPT2, SDRAM_MCOPT2_IPTR_EXECUTE); | |
190 | ||
191 | do { | |
192 | mfsdram(SDRAM_MCSTAT, reg); | |
193 | } while (!(reg & SDRAM_MCSTAT_MIC_COMP)); | |
194 | ||
195 | mfsdram(SDRAM_MCOPT2, reg); | |
196 | mtsdram(SDRAM_MCOPT2, reg | SDRAM_MCOPT2_DCEN_ENABLE); | |
197 | } | |
198 | ||
075d0b81 AG |
199 | static int ecc_check_status_reg(void) |
200 | { | |
201 | u32 ecc_status; | |
202 | ||
203 | /* | |
204 | * Compare suceeded, now check | |
205 | * if got ecc error. If got an | |
206 | * ecc error, then don't count | |
207 | * this as a passing value | |
208 | */ | |
fb95169e | 209 | mfsdram(SDRAM_ECCES, ecc_status); |
075d0b81 AG |
210 | if (ecc_status != 0x00000000) { |
211 | /* clear on error */ | |
212 | ecc_clear_status_reg(); | |
213 | /* ecc check failure */ | |
214 | return 0; | |
215 | } | |
216 | ecc_clear_status_reg(); | |
217 | sync(); | |
218 | ||
219 | return 1; | |
220 | } | |
221 | ||
222 | /* return 1 if passes, 0 if fail */ | |
223 | static int short_mem_test(u32 *base_address) | |
224 | { | |
225 | int i, j, l; | |
226 | u32 ecc_mode = 0; | |
227 | ||
228 | ulong test[NUMMEMTESTS][NUMMEMWORDS] = { | |
229 | /* 0 */ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
230 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
231 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
232 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, | |
233 | /* 1 */ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
234 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
235 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
236 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000}, | |
237 | /* 2 */ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
238 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
239 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
240 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555}, | |
241 | /* 3 */ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
242 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
243 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
244 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA}, | |
245 | /* 4 */ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
246 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
247 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
248 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A}, | |
249 | /* 5 */ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
250 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
251 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
252 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5}, | |
253 | /* 6 */ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
254 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
255 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
256 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA}, | |
257 | /* 7 */ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, | |
258 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, | |
259 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, | |
260 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55}, | |
261 | ||
6d0f6bcf | 262 | #if defined(CONFIG_SYS_DECREMENT_PATTERNS) |
075d0b81 AG |
263 | /* 8 */ {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, |
264 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, | |
265 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, | |
266 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, | |
267 | /* 9 */ {0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, | |
268 | 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, | |
269 | 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, | |
270 | 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe}, | |
271 | /* 10 */{0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, | |
272 | 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, | |
273 | 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, | |
274 | 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd}, | |
275 | /* 11 */{0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, | |
276 | 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, | |
277 | 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, | |
278 | 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc}, | |
279 | /* 12 */{0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, | |
280 | 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, | |
281 | 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, | |
282 | 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb}, | |
283 | /* 13 */{0xfffafffa, 0xfffafffa, 0xfffffffa, 0xfffafffa, | |
284 | 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, | |
285 | 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, | |
286 | 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa}, | |
287 | /* 14 */{0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, | |
288 | 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, | |
289 | 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, | |
290 | 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9}, | |
291 | /* 15 */{0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, | |
292 | 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, | |
293 | 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, | |
294 | 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8}, | |
295 | /* 16 */{0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, | |
296 | 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, | |
297 | 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, | |
298 | 0xfff7ffff, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7}, | |
299 | /* 17 */{0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, | |
300 | 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, | |
301 | 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, | |
302 | 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7}, | |
303 | /* 18 */{0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, | |
304 | 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, | |
305 | 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, | |
306 | 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5}, | |
307 | /* 19 */{0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, | |
308 | 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, | |
309 | 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, | |
310 | 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4}, | |
311 | /* 20 */{0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, | |
312 | 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, | |
313 | 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, | |
314 | 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3}, | |
315 | /* 21 */{0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, | |
316 | 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, | |
317 | 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, | |
318 | 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2}, | |
319 | /* 22 */{0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, | |
320 | 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, | |
321 | 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, | |
322 | 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1}, | |
323 | /* 23 */{0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, | |
324 | 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, | |
325 | 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, | |
326 | 0xfff0fff0, 0xfff0fffe, 0xfff0fff0, 0xfff0fff0}, | |
6d0f6bcf | 327 | #endif /* CONFIG_SYS_DECREMENT_PATTERNS */ |
075d0b81 AG |
328 | }; |
329 | ||
330 | mfsdram(SDRAM_MCOPT1, ecc_mode); | |
331 | if ((ecc_mode & SDRAM_MCOPT1_MCHK_CHK_REP) == | |
332 | SDRAM_MCOPT1_MCHK_CHK_REP) { | |
333 | ecc_clear_status_reg(); | |
334 | sync(); | |
335 | ecc_mode = 1; | |
336 | } else { | |
337 | ecc_mode = 0; | |
338 | } | |
339 | ||
340 | /* | |
341 | * Run the short memory test. | |
342 | */ | |
343 | for (i = 0; i < NUMMEMTESTS; i++) { | |
344 | for (j = 0; j < NUMMEMWORDS; j++) { | |
345 | base_address[j] = test[i][j]; | |
346 | ppcDcbf((ulong)&(base_address[j])); | |
347 | } | |
348 | sync(); | |
c645012a | 349 | iobarrier_rw(); |
075d0b81 AG |
350 | for (l = 0; l < NUMLOOPS; l++) { |
351 | for (j = 0; j < NUMMEMWORDS; j++) { | |
352 | if (base_address[j] != test[i][j]) { | |
353 | ppcDcbf((u32)&(base_address[j])); | |
354 | return 0; | |
355 | } else { | |
356 | if (ecc_mode) { | |
357 | if (!ecc_check_status_reg()) | |
358 | return 0; | |
359 | } | |
360 | } | |
361 | ppcDcbf((u32)&(base_address[j])); | |
362 | } /* for (j = 0; j < NUMMEMWORDS; j++) */ | |
363 | sync(); | |
c645012a | 364 | iobarrier_rw(); |
075d0b81 AG |
365 | } /* for (l=0; l<NUMLOOPS; l++) */ |
366 | } | |
367 | ||
368 | return 1; | |
369 | } | |
370 | ||
371 | #if defined(CONFIG_PPC4xx_DDR_METHOD_A) | |
372 | /*-----------------------------------------------------------------------------+ | |
373 | | program_DQS_calibration_methodA. | |
374 | +-----------------------------------------------------------------------------*/ | |
375 | static u32 program_DQS_calibration_methodA(struct ddrautocal *ddrcal) | |
376 | { | |
377 | u32 pass_result = 0; | |
378 | ||
379 | #ifdef DEBUG | |
380 | ulong temp; | |
381 | ||
382 | mfsdram(SDRAM_RDCC, temp); | |
383 | debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp); | |
384 | #endif | |
385 | ||
386 | pass_result = DQS_calibration_methodA(ddrcal); | |
387 | ||
388 | return pass_result; | |
389 | } | |
390 | ||
391 | /* | |
392 | * DQS_calibration_methodA() | |
393 | * | |
394 | * Autocalibration Method A | |
395 | * | |
396 | * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros | |
397 | * ARRAY [Entire FDBK Range] FDBK_Valid_Window; initialized to all zeros | |
398 | * MEMWRITE(addr, expected_data); | |
399 | * for (i = 0; i < Entire DQS Range; i++) { RQDC.RQFD | |
400 | * for (j = 0; j < Entire FDBK Range; j++) { RFDC.RFFD | |
401 | * MEMREAD(addr, actual_data); | |
402 | * if (actual_data == expected_data) { | |
403 | * DQS_Valid_Window[i] = 1; RQDC.RQFD | |
404 | * FDBK_Valid_Window[i][j] = 1; RFDC.RFFD | |
405 | * } | |
406 | * } | |
407 | * } | |
408 | */ | |
409 | static u32 DQS_calibration_methodA(struct ddrautocal *cal) | |
410 | { | |
411 | ulong rfdc_reg; | |
412 | ulong rffd; | |
413 | ||
414 | ulong rqdc_reg; | |
415 | ulong rqfd; | |
416 | ||
417 | u32 *membase; | |
418 | ulong bxcf; | |
419 | int rqfd_average; | |
420 | int bxcr_num; | |
421 | int rffd_average; | |
422 | int pass; | |
423 | u32 passed = 0; | |
424 | ||
425 | int in_window; | |
426 | struct autocal_regs curr_win_min; | |
427 | struct autocal_regs curr_win_max; | |
428 | struct autocal_regs best_win_min; | |
429 | struct autocal_regs best_win_max; | |
430 | struct autocal_regs loop_win_min; | |
431 | struct autocal_regs loop_win_max; | |
432 | ||
433 | #ifdef DEBUG | |
434 | ulong temp; | |
435 | #endif | |
436 | ulong rdcc; | |
437 | ||
438 | char slash[] = "\\|/-\\|/-"; | |
439 | int loopi = 0; | |
440 | ||
441 | /* start */ | |
442 | in_window = 0; | |
443 | ||
444 | memset(&curr_win_min, 0, sizeof(curr_win_min)); | |
445 | memset(&curr_win_max, 0, sizeof(curr_win_max)); | |
446 | memset(&best_win_min, 0, sizeof(best_win_min)); | |
447 | memset(&best_win_max, 0, sizeof(best_win_max)); | |
448 | memset(&loop_win_min, 0, sizeof(loop_win_min)); | |
449 | memset(&loop_win_max, 0, sizeof(loop_win_max)); | |
450 | ||
451 | rdcc = 0; | |
452 | ||
453 | /* | |
454 | * Program RDCC register | |
455 | * Read sample cycle auto-update enable | |
456 | */ | |
c645012a AG |
457 | mtsdram(SDRAM_RDCC, |
458 | ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE); | |
075d0b81 AG |
459 | |
460 | #ifdef DEBUG | |
461 | mfsdram(SDRAM_RDCC, temp); | |
462 | debug("<%s>SDRAM_RDCC=0x%x\n", __func__, temp); | |
463 | mfsdram(SDRAM_RTSR, temp); | |
464 | debug("<%s>SDRAM_RTSR=0x%x\n", __func__, temp); | |
465 | mfsdram(SDRAM_FCSR, temp); | |
466 | debug("<%s>SDRAM_FCSR=0x%x\n", __func__, temp); | |
467 | #endif | |
468 | ||
469 | /* | |
470 | * Program RQDC register | |
471 | * Internal DQS delay mechanism enable | |
472 | */ | |
473 | mtsdram(SDRAM_RQDC, | |
474 | SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x00)); | |
475 | ||
476 | #ifdef DEBUG | |
477 | mfsdram(SDRAM_RQDC, temp); | |
478 | debug("<%s>SDRAM_RQDC=0x%x\n", __func__, temp); | |
479 | #endif | |
480 | ||
481 | /* | |
482 | * Program RFDC register | |
483 | * Set Feedback Fractional Oversample | |
484 | * Auto-detect read sample cycle enable | |
485 | */ | |
486 | mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE | | |
487 | SDRAM_RFDC_RFOS_ENCODE(0) | SDRAM_RFDC_RFFD_ENCODE(0)); | |
488 | ||
489 | #ifdef DEBUG | |
490 | mfsdram(SDRAM_RFDC, temp); | |
491 | debug("<%s>SDRAM_RFDC=0x%x\n", __func__, temp); | |
492 | #endif | |
493 | ||
494 | putc(' '); | |
495 | for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) { | |
496 | ||
497 | mfsdram(SDRAM_RQDC, rqdc_reg); | |
498 | rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK); | |
499 | mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd)); | |
500 | ||
501 | putc('\b'); | |
502 | putc(slash[loopi++ % 8]); | |
503 | ||
504 | curr_win_min.rffd = 0; | |
505 | curr_win_max.rffd = 0; | |
506 | in_window = 0; | |
507 | ||
508 | for (rffd = 0, pass = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) { | |
509 | mfsdram(SDRAM_RFDC, rfdc_reg); | |
510 | rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); | |
511 | mtsdram(SDRAM_RFDC, | |
512 | rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd)); | |
513 | ||
514 | for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { | |
515 | mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); | |
516 | ||
517 | /* Banks enabled */ | |
518 | if (bxcf & SDRAM_BXCF_M_BE_MASK) { | |
519 | /* Bank is enabled */ | |
520 | membase = get_membase(bxcr_num); | |
521 | pass = short_mem_test(membase); | |
522 | } /* if bank enabled */ | |
523 | } /* for bxcr_num */ | |
524 | ||
525 | /* If this value passed update RFFD windows */ | |
526 | if (pass && !in_window) { /* at the start of window */ | |
527 | in_window = 1; | |
528 | curr_win_min.rffd = curr_win_max.rffd = rffd; | |
529 | curr_win_min.rqfd = curr_win_max.rqfd = rqfd; | |
530 | mfsdram(SDRAM_RDCC, rdcc); /*record this value*/ | |
531 | } else if (!pass && in_window) { /* at end of window */ | |
532 | in_window = 0; | |
533 | } else if (pass && in_window) { /* within the window */ | |
534 | curr_win_max.rffd = rffd; | |
535 | curr_win_max.rqfd = rqfd; | |
536 | } | |
537 | /* else if (!pass && !in_window) | |
538 | skip - no pass, not currently in a window */ | |
539 | ||
540 | if (in_window) { | |
541 | if ((curr_win_max.rffd - curr_win_min.rffd) > | |
542 | (best_win_max.rffd - best_win_min.rffd)) { | |
543 | best_win_min.rffd = curr_win_min.rffd; | |
544 | best_win_max.rffd = curr_win_max.rffd; | |
545 | ||
546 | best_win_min.rqfd = curr_win_min.rqfd; | |
547 | best_win_max.rqfd = curr_win_max.rqfd; | |
548 | cal->rdcc = rdcc; | |
549 | } | |
550 | passed = 1; | |
551 | } | |
552 | } /* RFDC.RFFD */ | |
553 | ||
554 | /* | |
555 | * save-off the best window results of the RFDC.RFFD | |
556 | * for this RQDC.RQFD setting | |
557 | */ | |
558 | /* | |
559 | * if (just ended RFDC.RFDC loop pass window) > | |
560 | * (prior RFDC.RFFD loop pass window) | |
561 | */ | |
562 | if ((best_win_max.rffd - best_win_min.rffd) > | |
563 | (loop_win_max.rffd - loop_win_min.rffd)) { | |
564 | loop_win_min.rffd = best_win_min.rffd; | |
565 | loop_win_max.rffd = best_win_max.rffd; | |
566 | loop_win_min.rqfd = rqfd; | |
567 | loop_win_max.rqfd = rqfd; | |
568 | debug("RQFD.min 0x%08x, RQFD.max 0x%08x, " | |
569 | "RFFD.min 0x%08x, RFFD.max 0x%08x\n", | |
570 | loop_win_min.rqfd, loop_win_max.rqfd, | |
571 | loop_win_min.rffd, loop_win_max.rffd); | |
572 | } | |
573 | } /* RQDC.RQFD */ | |
574 | ||
575 | putc('\b'); | |
576 | ||
577 | debug("\n"); | |
578 | ||
579 | if ((loop_win_min.rffd == 0) && (loop_win_max.rffd == 0) && | |
580 | (best_win_min.rffd == 0) && (best_win_max.rffd == 0) && | |
581 | (best_win_min.rqfd == 0) && (best_win_max.rqfd == 0)) { | |
582 | passed = 0; | |
583 | } | |
584 | ||
585 | /* | |
586 | * Need to program RQDC before RFDC. | |
587 | */ | |
588 | debug("<%s> RQFD Min: 0x%x\n", __func__, loop_win_min.rqfd); | |
589 | debug("<%s> RQFD Max: 0x%x\n", __func__, loop_win_max.rqfd); | |
590 | rqfd_average = loop_win_max.rqfd; | |
591 | ||
592 | if (rqfd_average < 0) | |
593 | rqfd_average = 0; | |
594 | ||
595 | if (rqfd_average > SDRAM_RQDC_RQFD_MAX) | |
596 | rqfd_average = SDRAM_RQDC_RQFD_MAX; | |
597 | ||
598 | debug("<%s> RFFD average: 0x%08x\n", __func__, rqfd_average); | |
599 | mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | | |
600 | SDRAM_RQDC_RQFD_ENCODE(rqfd_average)); | |
601 | ||
602 | debug("<%s> RFFD Min: 0x%08x\n", __func__, loop_win_min.rffd); | |
603 | debug("<%s> RFFD Max: 0x%08x\n", __func__, loop_win_max.rffd); | |
604 | rffd_average = ((loop_win_min.rffd + loop_win_max.rffd) / 2); | |
605 | ||
606 | if (rffd_average < 0) | |
607 | rffd_average = 0; | |
608 | ||
609 | if (rffd_average > SDRAM_RFDC_RFFD_MAX) | |
610 | rffd_average = SDRAM_RFDC_RFFD_MAX; | |
611 | ||
612 | debug("<%s> RFFD average: 0x%08x\n", __func__, rffd_average); | |
613 | mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); | |
614 | ||
615 | /* if something passed, then return the size of the largest window */ | |
616 | if (passed != 0) { | |
617 | passed = loop_win_max.rffd - loop_win_min.rffd; | |
618 | cal->rqfd = rqfd_average; | |
619 | cal->rffd = rffd_average; | |
620 | cal->rffd_min = loop_win_min.rffd; | |
621 | cal->rffd_max = loop_win_max.rffd; | |
622 | } | |
623 | ||
624 | return (u32)passed; | |
625 | } | |
626 | ||
627 | #else /* !defined(CONFIG_PPC4xx_DDR_METHOD_A) */ | |
628 | ||
629 | /*-----------------------------------------------------------------------------+ | |
630 | | program_DQS_calibration_methodB. | |
631 | +-----------------------------------------------------------------------------*/ | |
632 | static u32 program_DQS_calibration_methodB(struct ddrautocal *ddrcal) | |
633 | { | |
634 | u32 pass_result = 0; | |
635 | ||
636 | #ifdef DEBUG | |
637 | ulong temp; | |
638 | #endif | |
639 | ||
640 | /* | |
641 | * Program RDCC register | |
642 | * Read sample cycle auto-update enable | |
643 | */ | |
c645012a AG |
644 | mtsdram(SDRAM_RDCC, |
645 | ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE); | |
075d0b81 AG |
646 | |
647 | #ifdef DEBUG | |
648 | mfsdram(SDRAM_RDCC, temp); | |
649 | debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp); | |
650 | #endif | |
651 | ||
652 | /* | |
653 | * Program RQDC register | |
654 | * Internal DQS delay mechanism enable | |
655 | */ | |
656 | mtsdram(SDRAM_RQDC, | |
657 | #if defined(CONFIG_DDR_RQDC_START_VAL) | |
658 | SDRAM_RQDC_RQDE_ENABLE | | |
659 | SDRAM_RQDC_RQFD_ENCODE(CONFIG_DDR_RQDC_START_VAL)); | |
660 | #else | |
661 | SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x38)); | |
662 | #endif | |
663 | ||
664 | #ifdef DEBUG | |
665 | mfsdram(SDRAM_RQDC, temp); | |
666 | debug("<%s>SDRAM_RQDC=0x%08x\n", __func__, temp); | |
667 | #endif | |
668 | ||
669 | /* | |
670 | * Program RFDC register | |
671 | * Set Feedback Fractional Oversample | |
672 | * Auto-detect read sample cycle enable | |
673 | */ | |
674 | mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE | | |
675 | SDRAM_RFDC_RFOS_ENCODE(0) | | |
676 | SDRAM_RFDC_RFFD_ENCODE(0)); | |
677 | ||
678 | #ifdef DEBUG | |
679 | mfsdram(SDRAM_RFDC, temp); | |
680 | debug("<%s>SDRAM_RFDC=0x%08x\n", __func__, temp); | |
681 | #endif | |
682 | ||
683 | pass_result = DQS_calibration_methodB(ddrcal); | |
684 | ||
685 | return pass_result; | |
686 | } | |
687 | ||
688 | /* | |
689 | * DQS_calibration_methodB() | |
690 | * | |
691 | * Autocalibration Method B | |
692 | * | |
693 | * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros | |
694 | * ARRAY [Entire Feedback Range] FDBK_Valid_Window; initialized to all zeros | |
695 | * MEMWRITE(addr, expected_data); | |
696 | * Initialialize the DQS delay to 80 degrees (MCIF0_RRQDC[RQFD]=0x38). | |
697 | * | |
698 | * for (j = 0; j < Entire Feedback Range; j++) { | |
699 | * MEMREAD(addr, actual_data); | |
700 | * if (actual_data == expected_data) { | |
701 | * FDBK_Valid_Window[j] = 1; | |
702 | * } | |
703 | * } | |
704 | * | |
705 | * Set MCIF0_RFDC[RFFD] to the middle of the FDBK_Valid_Window. | |
706 | * | |
707 | * for (i = 0; i < Entire DQS Range; i++) { | |
708 | * MEMREAD(addr, actual_data); | |
709 | * if (actual_data == expected_data) { | |
710 | * DQS_Valid_Window[i] = 1; | |
711 | * } | |
712 | * } | |
713 | * | |
714 | * Set MCIF0_RRQDC[RQFD] to the middle of the DQS_Valid_Window. | |
715 | */ | |
716 | /*-----------------------------------------------------------------------------+ | |
717 | | DQS_calibration_methodB. | |
718 | +-----------------------------------------------------------------------------*/ | |
719 | static u32 DQS_calibration_methodB(struct ddrautocal *cal) | |
720 | { | |
721 | ulong rfdc_reg; | |
722 | ulong rffd; | |
723 | ||
724 | ulong rqdc_reg; | |
725 | ulong rqfd; | |
726 | ||
727 | ulong rdcc; | |
728 | ||
729 | u32 *membase; | |
730 | ulong bxcf; | |
731 | int rqfd_average; | |
732 | int bxcr_num; | |
733 | int rffd_average; | |
734 | int pass; | |
735 | uint passed = 0; | |
736 | ||
737 | int in_window; | |
738 | u32 curr_win_min, curr_win_max; | |
739 | u32 best_win_min, best_win_max; | |
740 | u32 size = 0; | |
741 | ||
742 | /*------------------------------------------------------------------ | |
743 | | Test to determine the best read clock delay tuning bits. | |
744 | | | |
745 | | Before the DDR controller can be used, the read clock delay needs to | |
746 | | be set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD]. | |
747 | | This value cannot be hardcoded into the program because it changes | |
748 | | depending on the board's setup and environment. | |
749 | | To do this, all delay values are tested to see if they | |
750 | | work or not. By doing this, you get groups of fails with groups of | |
751 | | passing values. The idea is to find the start and end of a passing | |
752 | | window and take the center of it to use as the read clock delay. | |
753 | | | |
754 | | A failure has to be seen first so that when we hit a pass, we know | |
755 | | that it is truely the start of the window. If we get passing values | |
756 | | to start off with, we don't know if we are at the start of the window | |
757 | | | |
758 | | The code assumes that a failure will always be found. | |
759 | | If a failure is not found, there is no easy way to get the middle | |
760 | | of the passing window. I guess we can pretty much pick any value | |
761 | | but some values will be better than others. Since the lowest speed | |
762 | | we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed), | |
763 | | from experimentation it is safe to say you will always have a failure | |
764 | +-----------------------------------------------------------------*/ | |
765 | ||
766 | debug("\n\n"); | |
767 | ||
eab98001 SR |
768 | #if defined(CONFIG_DDR_RFDC_FIXED) |
769 | mtsdram(SDRAM_RFDC, CONFIG_DDR_RFDC_FIXED); | |
770 | size = 512; | |
771 | rffd_average = CONFIG_DDR_RFDC_FIXED & SDRAM_RFDC_RFFD_MASK; | |
772 | mfsdram(SDRAM_RDCC, rdcc); /* record this value */ | |
773 | cal->rdcc = rdcc; | |
774 | #else /* CONFIG_DDR_RFDC_FIXED */ | |
075d0b81 AG |
775 | in_window = 0; |
776 | rdcc = 0; | |
777 | ||
778 | curr_win_min = curr_win_max = 0; | |
779 | best_win_min = best_win_max = 0; | |
780 | for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) { | |
781 | mfsdram(SDRAM_RFDC, rfdc_reg); | |
782 | rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); | |
783 | mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd)); | |
784 | ||
785 | pass = 1; | |
786 | for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { | |
787 | mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); | |
788 | ||
789 | /* Banks enabled */ | |
790 | if (bxcf & SDRAM_BXCF_M_BE_MASK) { | |
791 | /* Bank is enabled */ | |
792 | membase = get_membase(bxcr_num); | |
793 | pass &= short_mem_test(membase); | |
794 | } /* if bank enabled */ | |
795 | } /* for bxcf_num */ | |
796 | ||
797 | /* If this value passed */ | |
798 | if (pass && !in_window) { /* start of passing window */ | |
799 | in_window = 1; | |
800 | curr_win_min = curr_win_max = rffd; | |
801 | mfsdram(SDRAM_RDCC, rdcc); /* record this value */ | |
802 | } else if (!pass && in_window) { /* end passing window */ | |
803 | in_window = 0; | |
804 | } else if (pass && in_window) { /* within the passing window */ | |
805 | curr_win_max = rffd; | |
806 | } | |
807 | ||
808 | if (in_window) { | |
809 | if ((curr_win_max - curr_win_min) > | |
810 | (best_win_max - best_win_min)) { | |
811 | best_win_min = curr_win_min; | |
812 | best_win_max = curr_win_max; | |
813 | cal->rdcc = rdcc; | |
814 | } | |
815 | passed = 1; | |
816 | } | |
817 | } /* for rffd */ | |
818 | ||
819 | if ((best_win_min == 0) && (best_win_max == 0)) | |
820 | passed = 0; | |
821 | else | |
822 | size = best_win_max - best_win_min; | |
823 | ||
824 | debug("RFFD Min: 0x%x\n", best_win_min); | |
825 | debug("RFFD Max: 0x%x\n", best_win_max); | |
826 | rffd_average = ((best_win_min + best_win_max) / 2); | |
827 | ||
828 | cal->rffd_min = best_win_min; | |
829 | cal->rffd_max = best_win_max; | |
830 | ||
831 | if (rffd_average < 0) | |
832 | rffd_average = 0; | |
833 | ||
834 | if (rffd_average > SDRAM_RFDC_RFFD_MAX) | |
835 | rffd_average = SDRAM_RFDC_RFFD_MAX; | |
836 | ||
837 | mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); | |
eab98001 | 838 | #endif /* CONFIG_DDR_RFDC_FIXED */ |
075d0b81 AG |
839 | |
840 | rffd = rffd_average; | |
841 | in_window = 0; | |
842 | ||
843 | curr_win_min = curr_win_max = 0; | |
844 | best_win_min = best_win_max = 0; | |
845 | for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) { | |
846 | mfsdram(SDRAM_RQDC, rqdc_reg); | |
847 | rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK); | |
848 | mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd)); | |
849 | ||
850 | pass = 1; | |
851 | for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { | |
852 | ||
853 | mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); | |
854 | ||
855 | /* Banks enabled */ | |
856 | if (bxcf & SDRAM_BXCF_M_BE_MASK) { | |
857 | /* Bank is enabled */ | |
858 | membase = get_membase(bxcr_num); | |
859 | pass &= short_mem_test(membase); | |
860 | } /* if bank enabled */ | |
861 | } /* for bxcf_num */ | |
862 | ||
863 | /* If this value passed */ | |
864 | if (pass && !in_window) { | |
865 | in_window = 1; | |
866 | curr_win_min = curr_win_max = rqfd; | |
867 | } else if (!pass && in_window) { | |
868 | in_window = 0; | |
869 | } else if (pass && in_window) { | |
870 | curr_win_max = rqfd; | |
871 | } | |
872 | ||
873 | if (in_window) { | |
874 | if ((curr_win_max - curr_win_min) > | |
875 | (best_win_max - best_win_min)) { | |
876 | best_win_min = curr_win_min; | |
877 | best_win_max = curr_win_max; | |
878 | } | |
879 | passed = 1; | |
880 | } | |
881 | } /* for rqfd */ | |
882 | ||
883 | if ((best_win_min == 0) && (best_win_max == 0)) | |
884 | passed = 0; | |
885 | ||
886 | debug("RQFD Min: 0x%x\n", best_win_min); | |
887 | debug("RQFD Max: 0x%x\n", best_win_max); | |
888 | rqfd_average = ((best_win_min + best_win_max) / 2); | |
889 | ||
890 | if (rqfd_average < 0) | |
891 | rqfd_average = 0; | |
892 | ||
893 | if (rqfd_average > SDRAM_RQDC_RQFD_MAX) | |
894 | rqfd_average = SDRAM_RQDC_RQFD_MAX; | |
895 | ||
896 | mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | | |
897 | SDRAM_RQDC_RQFD_ENCODE(rqfd_average)); | |
898 | ||
899 | mfsdram(SDRAM_RQDC, rqdc_reg); | |
900 | mfsdram(SDRAM_RFDC, rfdc_reg); | |
901 | ||
902 | /* | |
903 | * Need to program RQDC before RFDC. The value is read above. | |
904 | * That is the reason why auto cal not work. | |
905 | * See, comments below. | |
906 | */ | |
907 | mtsdram(SDRAM_RQDC, rqdc_reg); | |
908 | mtsdram(SDRAM_RFDC, rfdc_reg); | |
909 | ||
bd78ef90 MV |
910 | debug("RQDC: 0x%08lX\n", rqdc_reg); |
911 | debug("RFDC: 0x%08lX\n", rfdc_reg); | |
075d0b81 AG |
912 | |
913 | /* if something passed, then return the size of the largest window */ | |
914 | if (passed != 0) { | |
915 | passed = size; | |
916 | cal->rqfd = rqfd_average; | |
917 | cal->rffd = rffd_average; | |
918 | } | |
919 | ||
920 | return (uint)passed; | |
921 | } | |
922 | #endif /* defined(CONFIG_PPC4xx_DDR_METHOD_A) */ | |
923 | ||
924 | /* | |
925 | * Default table for DDR auto-calibration of all | |
926 | * possible WRDTR and CLKTR values. | |
927 | * Table format is: | |
928 | * {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]} | |
929 | * | |
930 | * Table is terminated with {-1, -1} value pair. | |
931 | * | |
932 | * Board vendors can specify their own board specific subset of | |
933 | * known working {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]} value | |
934 | * pairs via a board defined ddr_scan_option() function. | |
935 | */ | |
066003b2 | 936 | static struct sdram_timing full_scan_options[] = { |
075d0b81 AG |
937 | {0, 0}, {0, 1}, {0, 2}, {0, 3}, |
938 | {1, 0}, {1, 1}, {1, 2}, {1, 3}, | |
939 | {2, 0}, {2, 1}, {2, 2}, {2, 3}, | |
940 | {3, 0}, {3, 1}, {3, 2}, {3, 3}, | |
941 | {4, 0}, {4, 1}, {4, 2}, {4, 3}, | |
942 | {5, 0}, {5, 1}, {5, 2}, {5, 3}, | |
943 | {6, 0}, {6, 1}, {6, 2}, {6, 3}, | |
944 | {-1, -1} | |
945 | }; | |
946 | ||
947 | /*---------------------------------------------------------------------------+ | |
948 | | DQS_calibration. | |
949 | +----------------------------------------------------------------------------*/ | |
950 | u32 DQS_autocalibration(void) | |
951 | { | |
952 | u32 wdtr; | |
953 | u32 clkp; | |
954 | u32 result = 0; | |
955 | u32 best_result = 0; | |
956 | u32 best_rdcc; | |
957 | struct ddrautocal ddrcal; | |
958 | struct autocal_clks tcal; | |
959 | ulong rfdc_reg; | |
960 | ulong rqdc_reg; | |
961 | u32 val; | |
962 | int verbose_lvl = 0; | |
963 | char *str; | |
964 | char slash[] = "\\|/-\\|/-"; | |
965 | int loopi = 0; | |
966 | struct sdram_timing *scan_list; | |
967 | ||
968 | #if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION) | |
969 | int i; | |
970 | char tmp[64]; /* long enough for environment variables */ | |
971 | #endif | |
972 | ||
973 | memset(&tcal, 0, sizeof(tcal)); | |
974 | ||
066003b2 | 975 | scan_list = ddr_scan_option(full_scan_options); |
075d0b81 AG |
976 | |
977 | mfsdram(SDRAM_MCOPT1, val); | |
978 | if ((val & SDRAM_MCOPT1_MCHK_CHK_REP) == SDRAM_MCOPT1_MCHK_CHK_REP) | |
979 | str = "ECC Auto calibration -"; | |
980 | else | |
981 | str = "Auto calibration -"; | |
982 | ||
983 | puts(str); | |
984 | ||
985 | #if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION) | |
cdb74977 | 986 | i = getenv_f("autocalib", tmp, sizeof(tmp)); |
075d0b81 AG |
987 | if (i < 0) |
988 | strcpy(tmp, CONFIG_AUTOCALIB); | |
989 | ||
990 | if (strcmp(tmp, "final") == 0) { | |
991 | /* display the final autocalibration results only */ | |
992 | verbose_lvl = 1; | |
993 | } else if (strcmp(tmp, "loop") == 0) { | |
994 | /* display summary autocalibration info per iteration */ | |
995 | verbose_lvl = 2; | |
996 | } else if (strcmp(tmp, "display") == 0) { | |
997 | /* display full debug autocalibration window info. */ | |
998 | verbose_lvl = 3; | |
999 | } | |
1000 | #endif /* (DEBUG_PPC4xx_DDR_AUTOCALIBRATION) */ | |
1001 | ||
1002 | best_rdcc = (SDRAM_RDCC_RDSS_T4 >> 30); | |
1003 | ||
1004 | while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) { | |
1005 | wdtr = scan_list->wrdtr; | |
1006 | clkp = scan_list->clktr; | |
1007 | ||
1008 | mfsdram(SDRAM_WRDTR, val); | |
1009 | val &= ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK); | |
1010 | mtsdram(SDRAM_WRDTR, (val | | |
1011 | ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | (wdtr << 25)))); | |
1012 | ||
1013 | mtsdram(SDRAM_CLKTR, clkp << 30); | |
1014 | ||
f8a00dea AG |
1015 | relock_memory_DLL(); |
1016 | ||
075d0b81 AG |
1017 | putc('\b'); |
1018 | putc(slash[loopi++ % 8]); | |
1019 | ||
1020 | #ifdef DEBUG | |
1021 | debug("\n"); | |
1022 | debug("*** --------------\n"); | |
1023 | mfsdram(SDRAM_WRDTR, val); | |
1024 | debug("*** SDRAM_WRDTR set to 0x%08x\n", val); | |
1025 | mfsdram(SDRAM_CLKTR, val); | |
1026 | debug("*** SDRAM_CLKTR set to 0x%08x\n", val); | |
1027 | #endif | |
1028 | ||
1029 | debug("\n"); | |
1030 | if (verbose_lvl > 2) { | |
1031 | printf("*** SDRAM_WRDTR (wdtr) set to %d\n", wdtr); | |
1032 | printf("*** SDRAM_CLKTR (clkp) set to %d\n", clkp); | |
1033 | } | |
1034 | ||
1035 | memset(&ddrcal, 0, sizeof(ddrcal)); | |
1036 | ||
1037 | /* | |
1038 | * DQS calibration. | |
1039 | */ | |
1040 | /* | |
1041 | * program_DQS_calibration_method[A|B]() returns 0 if no | |
1042 | * passing RFDC.[RFFD] window is found or returns the size | |
1043 | * of the best passing window; in the case of a found passing | |
1044 | * window, the ddrcal will contain the values of the best | |
1045 | * window RQDC.[RQFD] and RFDC.[RFFD]. | |
1046 | */ | |
1047 | ||
1048 | /* | |
1049 | * Call PPC4xx SDRAM DDR autocalibration methodA or methodB. | |
1050 | * Default is methodB. | |
1051 | * Defined the autocalibration method in the board specific | |
1052 | * header file. | |
1053 | * Please see include/configs/kilauea.h for an example for | |
1054 | * a board specific implementation. | |
1055 | */ | |
1056 | #if defined(CONFIG_PPC4xx_DDR_METHOD_A) | |
1057 | result = program_DQS_calibration_methodA(&ddrcal); | |
1058 | #else | |
1059 | result = program_DQS_calibration_methodB(&ddrcal); | |
1060 | #endif | |
1061 | ||
1062 | sync(); | |
1063 | ||
1064 | /* | |
1065 | * Clear potential errors resulting from auto-calibration. | |
1066 | * If not done, then we could get an interrupt later on when | |
1067 | * exceptions are enabled. | |
1068 | */ | |
1069 | set_mcsr(get_mcsr()); | |
1070 | ||
1071 | val = ddrcal.rdcc; /* RDCC from the best passing window */ | |
1072 | ||
1073 | udelay(100); | |
1074 | ||
1075 | if (verbose_lvl > 1) { | |
1076 | char *tstr; | |
1077 | switch ((val >> 30)) { | |
1078 | case 0: | |
1079 | if (result != 0) | |
1080 | tstr = "T1"; | |
1081 | else | |
1082 | tstr = "N/A"; | |
1083 | break; | |
1084 | case 1: | |
1085 | tstr = "T2"; | |
1086 | break; | |
1087 | case 2: | |
1088 | tstr = "T3"; | |
1089 | break; | |
1090 | case 3: | |
1091 | tstr = "T4"; | |
1092 | break; | |
1093 | default: | |
1094 | tstr = "unknown"; | |
1095 | break; | |
1096 | } | |
1097 | printf("** WRDTR(%d) CLKTR(%d), Wind (%d), best (%d), " | |
1098 | "max-min(0x%04x)(0x%04x), RDCC: %s\n", | |
1099 | wdtr, clkp, result, best_result, | |
1100 | ddrcal.rffd_min, ddrcal.rffd_max, tstr); | |
1101 | } | |
1102 | ||
1103 | /* | |
1104 | * The DQS calibration "result" is either "0" | |
1105 | * if no passing window was found, or is the | |
1106 | * size of the RFFD passing window. | |
1107 | */ | |
c645012a AG |
1108 | /* |
1109 | * want the lowest Read Sample Cycle Select | |
1110 | */ | |
1111 | val = SDRAM_RDCC_RDSS_DECODE(val); | |
1112 | debug("*** (%d) (%d) current_rdcc, best_rdcc\n", | |
1113 | val, best_rdcc); | |
1114 | ||
1115 | if ((result != 0) && | |
1116 | (val >= SDRAM_RDCC_RDSS_VAL(SDRAM_RDCC_RDSS_T2))) { | |
1117 | if (((result == best_result) && (val < best_rdcc)) || | |
1118 | ((result > best_result) && (val <= best_rdcc))) { | |
1119 | tcal.autocal.flags = 1; | |
1120 | debug("*** (%d)(%d) result passed window " | |
1121 | "size: 0x%08x, rqfd = 0x%08x, " | |
1122 | "rffd = 0x%08x, rdcc = 0x%08x\n", | |
1123 | wdtr, clkp, result, ddrcal.rqfd, | |
1124 | ddrcal.rffd, ddrcal.rdcc); | |
1125 | ||
075d0b81 | 1126 | /* |
c645012a AG |
1127 | * Save the SDRAM_WRDTR and SDRAM_CLKTR |
1128 | * settings for the largest returned | |
1129 | * RFFD passing window size. | |
075d0b81 | 1130 | */ |
c645012a AG |
1131 | best_rdcc = val; |
1132 | tcal.clocks.wrdtr = wdtr; | |
1133 | tcal.clocks.clktr = clkp; | |
1134 | tcal.clocks.rdcc = SDRAM_RDCC_RDSS_ENCODE(val); | |
1135 | tcal.autocal.rqfd = ddrcal.rqfd; | |
1136 | tcal.autocal.rffd = ddrcal.rffd; | |
1137 | best_result = result; | |
075d0b81 AG |
1138 | |
1139 | if (verbose_lvl > 2) { | |
1140 | printf("** (%d)(%d) " | |
1141 | "best result: 0x%04x\n", | |
1142 | wdtr, clkp, | |
1143 | best_result); | |
1144 | printf("** (%d)(%d) " | |
1145 | "best WRDTR: 0x%04x\n", | |
1146 | wdtr, clkp, | |
1147 | tcal.clocks.wrdtr); | |
1148 | printf("** (%d)(%d) " | |
1149 | "best CLKTR: 0x%04x\n", | |
1150 | wdtr, clkp, | |
1151 | tcal.clocks.clktr); | |
1152 | printf("** (%d)(%d) " | |
1153 | "best RQDC: 0x%04x\n", | |
1154 | wdtr, clkp, | |
1155 | tcal.autocal.rqfd); | |
1156 | printf("** (%d)(%d) " | |
1157 | "best RFDC: 0x%04x\n", | |
1158 | wdtr, clkp, | |
1159 | tcal.autocal.rffd); | |
1160 | printf("** (%d)(%d) " | |
1161 | "best RDCC: 0x%08x\n", | |
1162 | wdtr, clkp, | |
1163 | (u32)tcal.clocks.rdcc); | |
1164 | mfsdram(SDRAM_RTSR, val); | |
1165 | printf("** (%d)(%d) best " | |
1166 | "loop RTSR: 0x%08x\n", | |
1167 | wdtr, clkp, val); | |
1168 | mfsdram(SDRAM_FCSR, val); | |
1169 | printf("** (%d)(%d) best " | |
1170 | "loop FCSR: 0x%08x\n", | |
1171 | wdtr, clkp, val); | |
1172 | } | |
c645012a AG |
1173 | } |
1174 | } /* if ((result != 0) && (val >= (ddr_rdss_opt()))) */ | |
075d0b81 AG |
1175 | scan_list++; |
1176 | } /* while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) */ | |
1177 | ||
1178 | if (tcal.autocal.flags == 1) { | |
1179 | if (verbose_lvl > 0) { | |
1180 | printf("*** --------------\n"); | |
1181 | printf("*** best_result window size: %d\n", | |
1182 | best_result); | |
1183 | printf("*** best_result WRDTR: 0x%04x\n", | |
1184 | tcal.clocks.wrdtr); | |
1185 | printf("*** best_result CLKTR: 0x%04x\n", | |
1186 | tcal.clocks.clktr); | |
1187 | printf("*** best_result RQFD: 0x%04x\n", | |
1188 | tcal.autocal.rqfd); | |
1189 | printf("*** best_result RFFD: 0x%04x\n", | |
1190 | tcal.autocal.rffd); | |
1191 | printf("*** best_result RDCC: 0x%04x\n", | |
1192 | tcal.clocks.rdcc); | |
1193 | printf("*** --------------\n"); | |
1194 | printf("\n"); | |
1195 | } | |
1196 | ||
1197 | /* | |
1198 | * if got best passing result window, then lock in the | |
1199 | * best CLKTR, WRDTR, RQFD, and RFFD values | |
1200 | */ | |
1201 | mfsdram(SDRAM_WRDTR, val); | |
1202 | mtsdram(SDRAM_WRDTR, (val & | |
1203 | ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) | | |
1204 | ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | | |
1205 | (tcal.clocks.wrdtr << 25))); | |
1206 | ||
1207 | mtsdram(SDRAM_CLKTR, tcal.clocks.clktr << 30); | |
1208 | ||
f8a00dea AG |
1209 | relock_memory_DLL(); |
1210 | ||
075d0b81 AG |
1211 | mfsdram(SDRAM_RQDC, rqdc_reg); |
1212 | rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK); | |
1213 | mtsdram(SDRAM_RQDC, rqdc_reg | | |
1214 | SDRAM_RQDC_RQFD_ENCODE(tcal.autocal.rqfd)); | |
1215 | ||
1216 | mfsdram(SDRAM_RQDC, rqdc_reg); | |
bd78ef90 | 1217 | debug("*** best_result: read value SDRAM_RQDC 0x%08lx\n", |
075d0b81 AG |
1218 | rqdc_reg); |
1219 | ||
eab98001 SR |
1220 | #if defined(CONFIG_DDR_RFDC_FIXED) |
1221 | mtsdram(SDRAM_RFDC, CONFIG_DDR_RFDC_FIXED); | |
1222 | #else /* CONFIG_DDR_RFDC_FIXED */ | |
075d0b81 AG |
1223 | mfsdram(SDRAM_RFDC, rfdc_reg); |
1224 | rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); | |
1225 | mtsdram(SDRAM_RFDC, rfdc_reg | | |
1226 | SDRAM_RFDC_RFFD_ENCODE(tcal.autocal.rffd)); | |
eab98001 | 1227 | #endif /* CONFIG_DDR_RFDC_FIXED */ |
075d0b81 AG |
1228 | |
1229 | mfsdram(SDRAM_RFDC, rfdc_reg); | |
bd78ef90 | 1230 | debug("*** best_result: read value SDRAM_RFDC 0x%08lx\n", |
075d0b81 AG |
1231 | rfdc_reg); |
1232 | mfsdram(SDRAM_RDCC, val); | |
1233 | debug("*** SDRAM_RDCC 0x%08x\n", val); | |
1234 | } else { | |
1235 | /* | |
1236 | * no valid windows were found | |
1237 | */ | |
1238 | printf("DQS memory calibration window can not be determined, " | |
1239 | "terminating u-boot.\n"); | |
1240 | ppc4xx_ibm_ddr2_register_dump(); | |
1241 | spd_ddr_init_hang(); | |
1242 | } | |
1243 | ||
1244 | blank_string(strlen(str)); | |
1245 | ||
1246 | return 0; | |
1247 | } | |
1248 | #else /* defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */ | |
1249 | u32 DQS_autocalibration(void) | |
1250 | { | |
1251 | return 0; | |
1252 | } | |
1253 | #endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */ |