]>
Commit | Line | Data |
---|---|---|
8a24a696 | 1 | /* |
a47a12be | 2 | * arch/powerpc/cpu/ppc4xx/denali_data_eye.c |
8a24a696 LJ |
3 | * Extracted from board/amcc/sequoia/sdram.c by Larry Johnson <lrj@acm.org>. |
4 | * | |
5 | * (C) Copyright 2006 | |
6 | * Sylvie Gohl, AMCC/IBM, gohl.sylvie@fr.ibm.com | |
7 | * Jacqueline Pira-Ferriol, AMCC/IBM, jpira-ferriol@fr.ibm.com | |
8 | * Thierry Roman, AMCC/IBM, thierry_roman@fr.ibm.com | |
9 | * Alain Saurel, AMCC/IBM, alain.saurel@fr.ibm.com | |
10 | * Robert Snyder, AMCC/IBM, rob.snyder@fr.ibm.com | |
11 | * | |
12 | * (C) Copyright 2006-2007 | |
13 | * Stefan Roese, DENX Software Engineering, sr@denx.de. | |
14 | * | |
1a459660 | 15 | * SPDX-License-Identifier: GPL-2.0+ |
8a24a696 LJ |
16 | */ |
17 | ||
18 | /* define DEBUG for debugging output (obviously ;-)) */ | |
19 | #if 0 | |
20 | #define DEBUG | |
21 | #endif | |
22 | ||
23 | #include <common.h> | |
24 | #include <asm/processor.h> | |
25 | #include <asm/io.h> | |
b36df561 | 26 | #include <asm/ppc4xx.h> |
8a24a696 LJ |
27 | |
28 | #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) | |
29 | /*-----------------------------------------------------------------------------+ | |
30 | * denali_wait_for_dlllock. | |
31 | +----------------------------------------------------------------------------*/ | |
32 | int denali_wait_for_dlllock(void) | |
33 | { | |
34 | u32 val; | |
35 | int wait; | |
36 | ||
37 | /* -----------------------------------------------------------+ | |
38 | * Wait for the DCC master delay line to finish calibration | |
39 | * ----------------------------------------------------------*/ | |
40 | for (wait = 0; wait != 0xffff; ++wait) { | |
41 | mfsdram(DDR0_17, val); | |
42 | if (DDR0_17_DLLLOCKREG_DECODE(val)) { | |
43 | /* dlllockreg bit on */ | |
44 | return 0; | |
45 | } | |
46 | } | |
47 | debug("0x%04x: DDR0_17 Value (dlllockreg bit): 0x%08x\n", wait, val); | |
48 | debug("Waiting for dlllockreg bit to raise\n"); | |
49 | return -1; | |
50 | } | |
51 | ||
52 | #if defined(CONFIG_DDR_DATA_EYE) | |
53 | #define DDR_DCR_BASE 0x10 | |
54 | #define ddrcfga (DDR_DCR_BASE+0x0) /* DDR configuration address reg */ | |
55 | #define ddrcfgd (DDR_DCR_BASE+0x1) /* DDR configuration data reg */ | |
56 | ||
57 | /*-----------------------------------------------------------------------------+ | |
58 | * wait_for_dram_init_complete. | |
59 | +----------------------------------------------------------------------------*/ | |
60 | static int wait_for_dram_init_complete(void) | |
61 | { | |
62 | unsigned long val; | |
63 | int wait = 0; | |
64 | ||
65 | /* --------------------------------------------------------------+ | |
66 | * Wait for 'DRAM initialization complete' bit in status register | |
67 | * -------------------------------------------------------------*/ | |
68 | mtdcr(ddrcfga, DDR0_00); | |
69 | ||
70 | while (wait != 0xffff) { | |
71 | val = mfdcr(ddrcfgd); | |
72 | if ((val & DDR0_00_INT_STATUS_BIT6) == DDR0_00_INT_STATUS_BIT6) | |
73 | /* 'DRAM initialization complete' bit */ | |
74 | return 0; | |
75 | else | |
76 | wait++; | |
77 | } | |
78 | debug("DRAM initialization complete bit in status register did not " | |
79 | "rise\n"); | |
80 | return -1; | |
81 | } | |
82 | ||
83 | #define NUM_TRIES 64 | |
84 | #define NUM_READS 10 | |
85 | ||
86 | /*-----------------------------------------------------------------------------+ | |
87 | * denali_core_search_data_eye. | |
88 | +----------------------------------------------------------------------------*/ | |
8a24a696 | 89 | void denali_core_search_data_eye(void) |
8a24a696 LJ |
90 | { |
91 | int k, j; | |
92 | u32 val; | |
93 | u32 wr_dqs_shift, dqs_out_shift, dll_dqs_delay_X; | |
94 | u32 max_passing_cases = 0, wr_dqs_shift_with_max_passing_cases = 0; | |
95 | u32 passing_cases = 0, dll_dqs_delay_X_sw_val = 0; | |
96 | u32 dll_dqs_delay_X_start_window = 0, dll_dqs_delay_X_end_window = 0; | |
97 | volatile u32 *ram_pointer; | |
98 | u32 test[NUM_TRIES] = { | |
99 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
100 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
101 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
102 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
103 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
104 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
105 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
106 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
107 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
108 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
109 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
110 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
111 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
112 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
113 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, | |
114 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 | |
115 | }; | |
116 | ||
6d0f6bcf | 117 | ram_pointer = (volatile u32 *)(CONFIG_SYS_SDRAM_BASE); |
8a24a696 LJ |
118 | |
119 | for (wr_dqs_shift = 64; wr_dqs_shift < 96; wr_dqs_shift++) { | |
120 | /* for (wr_dqs_shift=1; wr_dqs_shift<96; wr_dqs_shift++) { */ | |
121 | ||
122 | /* -----------------------------------------------------------+ | |
123 | * De-assert 'start' parameter. | |
124 | * ----------------------------------------------------------*/ | |
125 | mtdcr(ddrcfga, DDR0_02); | |
126 | val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | | |
127 | DDR0_02_START_OFF; | |
128 | mtdcr(ddrcfgd, val); | |
129 | ||
130 | /* -----------------------------------------------------------+ | |
131 | * Set 'wr_dqs_shift' | |
132 | * ----------------------------------------------------------*/ | |
133 | mtdcr(ddrcfga, DDR0_09); | |
134 | val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK) | | |
135 | DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift); | |
136 | mtdcr(ddrcfgd, val); | |
137 | ||
138 | /* -----------------------------------------------------------+ | |
139 | * Set 'dqs_out_shift' = wr_dqs_shift + 32 | |
140 | * ----------------------------------------------------------*/ | |
141 | dqs_out_shift = wr_dqs_shift + 32; | |
142 | mtdcr(ddrcfga, DDR0_22); | |
143 | val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK) | | |
144 | DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift); | |
145 | mtdcr(ddrcfgd, val); | |
146 | ||
147 | passing_cases = 0; | |
148 | ||
149 | for (dll_dqs_delay_X = 1; dll_dqs_delay_X < 64; | |
150 | dll_dqs_delay_X++) { | |
151 | /* for (dll_dqs_delay_X=1; dll_dqs_delay_X<128; | |
152 | dll_dqs_delay_X++) { */ | |
153 | /* -----------------------------------------------------------+ | |
154 | * Set 'dll_dqs_delay_X'. | |
155 | * ----------------------------------------------------------*/ | |
156 | /* dll_dqs_delay_0 */ | |
157 | mtdcr(ddrcfga, DDR0_17); | |
158 | val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK) | |
159 | | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X); | |
160 | mtdcr(ddrcfgd, val); | |
161 | /* dll_dqs_delay_1 to dll_dqs_delay_4 */ | |
162 | mtdcr(ddrcfga, DDR0_18); | |
163 | val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK) | |
164 | | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X) | |
165 | | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X) | |
166 | | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X) | |
167 | | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X); | |
168 | mtdcr(ddrcfgd, val); | |
169 | /* dll_dqs_delay_5 to dll_dqs_delay_8 */ | |
170 | mtdcr(ddrcfga, DDR0_19); | |
171 | val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK) | |
172 | | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X) | |
173 | | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X) | |
174 | | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X) | |
175 | | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X); | |
176 | mtdcr(ddrcfgd, val); | |
177 | /* clear any ECC errors */ | |
178 | mtdcr(ddrcfga, DDR0_00); | |
179 | mtdcr(ddrcfgd, | |
180 | mfdcr(ddrcfgd) | DDR0_00_INT_ACK_ENCODE(0x3C)); | |
181 | ||
182 | sync(); | |
183 | eieio(); | |
184 | ||
185 | /* -----------------------------------------------------------+ | |
186 | * Assert 'start' parameter. | |
187 | * ----------------------------------------------------------*/ | |
188 | mtdcr(ddrcfga, DDR0_02); | |
189 | val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | | |
190 | DDR0_02_START_ON; | |
191 | mtdcr(ddrcfgd, val); | |
192 | ||
193 | sync(); | |
194 | eieio(); | |
195 | ||
196 | /* -----------------------------------------------------------+ | |
197 | * Wait for the DCC master delay line to finish calibration | |
198 | * ----------------------------------------------------------*/ | |
199 | if (denali_wait_for_dlllock() != 0) { | |
200 | printf("dll lock did not occur !!!\n"); | |
201 | printf("denali_core_search_data_eye!!!\n"); | |
202 | printf("wr_dqs_shift = %d - dll_dqs_delay_X = " | |
203 | "%d\n", wr_dqs_shift, dll_dqs_delay_X); | |
204 | hang(); | |
205 | } | |
206 | sync(); | |
207 | eieio(); | |
208 | ||
209 | if (wait_for_dram_init_complete() != 0) { | |
210 | printf("dram init complete did not occur!!!\n"); | |
211 | printf("denali_core_search_data_eye!!!\n"); | |
212 | printf("wr_dqs_shift = %d - dll_dqs_delay_X = " | |
213 | "%d\n", wr_dqs_shift, dll_dqs_delay_X); | |
214 | hang(); | |
215 | } | |
216 | udelay(100); /* wait 100us to ensure init is really completed !!! */ | |
217 | ||
218 | /* write values */ | |
219 | for (j = 0; j < NUM_TRIES; j++) { | |
220 | ram_pointer[j] = test[j]; | |
221 | ||
222 | /* clear any cache at ram location */ | |
223 | __asm__("dcbf 0,%0": :"r"(&ram_pointer[j])); | |
224 | } | |
225 | ||
226 | /* read values back */ | |
227 | for (j = 0; j < NUM_TRIES; j++) { | |
228 | for (k = 0; k < NUM_READS; k++) { | |
229 | /* clear any cache at ram location */ | |
230 | __asm__("dcbf 0,%0": :"r"(&ram_pointer | |
231 | [j])); | |
232 | ||
233 | if (ram_pointer[j] != test[j]) | |
234 | break; | |
235 | } | |
236 | ||
237 | /* read error */ | |
238 | if (k != NUM_READS) | |
239 | break; | |
240 | } | |
241 | ||
242 | /* See if the dll_dqs_delay_X value passed. */ | |
243 | mtdcr(ddrcfga, DDR0_00); | |
244 | if (j < NUM_TRIES | |
245 | || (DDR0_00_INT_STATUS_DECODE(mfdcr(ddrcfgd)) & | |
246 | 0x3F)) { | |
247 | /* Failed */ | |
248 | passing_cases = 0; | |
249 | /* break; */ | |
250 | } else { | |
251 | /* Passed */ | |
252 | if (passing_cases == 0) | |
253 | dll_dqs_delay_X_sw_val = | |
254 | dll_dqs_delay_X; | |
255 | passing_cases++; | |
256 | if (passing_cases >= max_passing_cases) { | |
257 | max_passing_cases = passing_cases; | |
258 | wr_dqs_shift_with_max_passing_cases = | |
259 | wr_dqs_shift; | |
260 | dll_dqs_delay_X_start_window = | |
261 | dll_dqs_delay_X_sw_val; | |
262 | dll_dqs_delay_X_end_window = | |
263 | dll_dqs_delay_X; | |
264 | } | |
265 | } | |
266 | ||
267 | /* -----------------------------------------------------------+ | |
268 | * De-assert 'start' parameter. | |
269 | * ----------------------------------------------------------*/ | |
270 | mtdcr(ddrcfga, DDR0_02); | |
271 | val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | | |
272 | DDR0_02_START_OFF; | |
273 | mtdcr(ddrcfgd, val); | |
274 | } /* for (dll_dqs_delay_X=0; dll_dqs_delay_X<128; dll_dqs_delay_X++) */ | |
275 | } /* for (wr_dqs_shift=0; wr_dqs_shift<96; wr_dqs_shift++) */ | |
276 | ||
277 | /* -----------------------------------------------------------+ | |
278 | * Largest passing window is now detected. | |
279 | * ----------------------------------------------------------*/ | |
280 | ||
281 | /* Compute dll_dqs_delay_X value */ | |
282 | dll_dqs_delay_X = (dll_dqs_delay_X_end_window + | |
283 | dll_dqs_delay_X_start_window) / 2; | |
284 | wr_dqs_shift = wr_dqs_shift_with_max_passing_cases; | |
285 | ||
286 | debug("DQS calibration - Window detected:\n"); | |
287 | debug("max_passing_cases = %d\n", max_passing_cases); | |
288 | debug("wr_dqs_shift = %d\n", wr_dqs_shift); | |
289 | debug("dll_dqs_delay_X = %d\n", dll_dqs_delay_X); | |
290 | debug("dll_dqs_delay_X window = %d - %d\n", | |
291 | dll_dqs_delay_X_start_window, dll_dqs_delay_X_end_window); | |
292 | ||
293 | /* -----------------------------------------------------------+ | |
294 | * De-assert 'start' parameter. | |
295 | * ----------------------------------------------------------*/ | |
296 | mtdcr(ddrcfga, DDR0_02); | |
297 | val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_OFF; | |
298 | mtdcr(ddrcfgd, val); | |
299 | ||
300 | /* -----------------------------------------------------------+ | |
301 | * Set 'wr_dqs_shift' | |
302 | * ----------------------------------------------------------*/ | |
303 | mtdcr(ddrcfga, DDR0_09); | |
304 | val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK) | |
305 | | DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift); | |
306 | mtdcr(ddrcfgd, val); | |
b6d5040b | 307 | debug("DDR0_09=0x%08x\n", val); |
8a24a696 LJ |
308 | |
309 | /* -----------------------------------------------------------+ | |
310 | * Set 'dqs_out_shift' = wr_dqs_shift + 32 | |
311 | * ----------------------------------------------------------*/ | |
312 | dqs_out_shift = wr_dqs_shift + 32; | |
313 | mtdcr(ddrcfga, DDR0_22); | |
314 | val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK) | |
315 | | DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift); | |
316 | mtdcr(ddrcfgd, val); | |
b6d5040b | 317 | debug("DDR0_22=0x%08x\n", val); |
8a24a696 LJ |
318 | |
319 | /* -----------------------------------------------------------+ | |
320 | * Set 'dll_dqs_delay_X'. | |
321 | * ----------------------------------------------------------*/ | |
322 | /* dll_dqs_delay_0 */ | |
323 | mtdcr(ddrcfga, DDR0_17); | |
324 | val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK) | |
325 | | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X); | |
326 | mtdcr(ddrcfgd, val); | |
b6d5040b | 327 | debug("DDR0_17=0x%08x\n", val); |
8a24a696 LJ |
328 | |
329 | /* dll_dqs_delay_1 to dll_dqs_delay_4 */ | |
330 | mtdcr(ddrcfga, DDR0_18); | |
331 | val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK) | |
332 | | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X) | |
333 | | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X) | |
334 | | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X) | |
335 | | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X); | |
336 | mtdcr(ddrcfgd, val); | |
b6d5040b | 337 | debug("DDR0_18=0x%08x\n", val); |
8a24a696 LJ |
338 | |
339 | /* dll_dqs_delay_5 to dll_dqs_delay_8 */ | |
340 | mtdcr(ddrcfga, DDR0_19); | |
341 | val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK) | |
342 | | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X) | |
343 | | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X) | |
344 | | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X) | |
345 | | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X); | |
346 | mtdcr(ddrcfgd, val); | |
b6d5040b | 347 | debug("DDR0_19=0x%08x\n", val); |
8a24a696 LJ |
348 | |
349 | /* -----------------------------------------------------------+ | |
350 | * Assert 'start' parameter. | |
351 | * ----------------------------------------------------------*/ | |
352 | mtdcr(ddrcfga, DDR0_02); | |
353 | val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_ON; | |
354 | mtdcr(ddrcfgd, val); | |
355 | ||
356 | sync(); | |
357 | eieio(); | |
358 | ||
359 | /* -----------------------------------------------------------+ | |
360 | * Wait for the DCC master delay line to finish calibration | |
361 | * ----------------------------------------------------------*/ | |
362 | if (denali_wait_for_dlllock() != 0) { | |
363 | printf("dll lock did not occur !!!\n"); | |
364 | hang(); | |
365 | } | |
366 | sync(); | |
367 | eieio(); | |
368 | ||
369 | if (wait_for_dram_init_complete() != 0) { | |
370 | printf("dram init complete did not occur !!!\n"); | |
371 | hang(); | |
372 | } | |
373 | udelay(100); /* wait 100us to ensure init is really completed !!! */ | |
374 | } | |
375 | #endif /* defined(CONFIG_DDR_DATA_EYE) */ | |
376 | #endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */ |