]>
Commit | Line | Data |
---|---|---|
58e5e9af | 1 | /* |
34e026f9 | 2 | * Copyright 2008-2014 Freescale Semiconductor, Inc. |
58e5e9af | 3 | * |
5b8031cc | 4 | * SPDX-License-Identifier: GPL-2.0 |
58e5e9af KG |
5 | */ |
6 | ||
7 | #include <common.h> | |
9ac4ffbd | 8 | #ifdef CONFIG_PPC |
58e5e9af | 9 | #include <asm/fsl_law.h> |
9ac4ffbd | 10 | #endif |
e820a131 | 11 | #include <div64.h> |
58e5e9af | 12 | |
5614e71b | 13 | #include <fsl_ddr.h> |
9a17eb5b | 14 | #include <fsl_immap.h> |
5614e71b | 15 | #include <asm/io.h> |
58e5e9af | 16 | |
e820a131 | 17 | /* To avoid 64-bit full-divides, we factor this here */ |
a2879634 KM |
18 | #define ULL_2E12 2000000000000ULL |
19 | #define UL_5POW12 244140625UL | |
20 | #define UL_2POW13 (1UL << 13) | |
e820a131 | 21 | |
a2879634 | 22 | #define ULL_8FS 0xFFFFFFFFULL |
e820a131 | 23 | |
66869f95 | 24 | u32 fsl_ddr_get_version(unsigned int ctrl_num) |
34e026f9 YS |
25 | { |
26 | struct ccsr_ddr __iomem *ddr; | |
27 | u32 ver_major_minor_errata; | |
28 | ||
66869f95 YS |
29 | switch (ctrl_num) { |
30 | case 0: | |
31 | ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; | |
32 | break; | |
33 | #if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) | |
34 | case 1: | |
35 | ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; | |
36 | break; | |
37 | #endif | |
38 | #if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) | |
39 | case 2: | |
40 | ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; | |
41 | break; | |
42 | #endif | |
43 | #if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) | |
44 | case 3: | |
45 | ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; | |
46 | break; | |
47 | #endif | |
48 | default: | |
49 | printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); | |
50 | return 0; | |
51 | } | |
34e026f9 YS |
52 | ver_major_minor_errata = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8; |
53 | ver_major_minor_errata |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8; | |
54 | ||
55 | return ver_major_minor_errata; | |
56 | } | |
57 | ||
58e5e9af | 58 | /* |
905acde2 YS |
59 | * Round up mclk_ps to nearest 1 ps in memory controller code |
60 | * if the error is 0.5ps or more. | |
58e5e9af KG |
61 | * |
62 | * If an imprecise data rate is too high due to rounding error | |
63 | * propagation, compute a suitably rounded mclk_ps to compute | |
64 | * a working memory controller configuration. | |
65 | */ | |
03e664d8 | 66 | unsigned int get_memory_clk_period_ps(const unsigned int ctrl_num) |
58e5e9af | 67 | { |
03e664d8 | 68 | unsigned int data_rate = get_ddr_freq(ctrl_num); |
e820a131 KM |
69 | unsigned int result; |
70 | ||
71 | /* Round to nearest 10ps, being careful about 64-bit multiply/divide */ | |
905acde2 | 72 | unsigned long long rem, mclk_ps = ULL_2E12; |
e820a131 KM |
73 | |
74 | /* Now perform the big divide, the result fits in 32-bits */ | |
905acde2 YS |
75 | rem = do_div(mclk_ps, data_rate); |
76 | result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps; | |
58e5e9af | 77 | |
905acde2 | 78 | return result; |
58e5e9af KG |
79 | } |
80 | ||
81 | /* Convert picoseconds into DRAM clock cycles (rounding up if needed). */ | |
03e664d8 | 82 | unsigned int picos_to_mclk(const unsigned int ctrl_num, unsigned int picos) |
58e5e9af | 83 | { |
e820a131 | 84 | unsigned long long clks, clks_rem; |
03e664d8 | 85 | unsigned long data_rate = get_ddr_freq(ctrl_num); |
58e5e9af | 86 | |
e820a131 | 87 | /* Short circuit for zero picos */ |
58e5e9af KG |
88 | if (!picos) |
89 | return 0; | |
90 | ||
e820a131 | 91 | /* First multiply the time by the data rate (32x32 => 64) */ |
905acde2 | 92 | clks = picos * (unsigned long long)data_rate; |
e820a131 KM |
93 | /* |
94 | * Now divide by 5^12 and track the 32-bit remainder, then divide | |
95 | * by 2*(2^12) using shifts (and updating the remainder). | |
96 | */ | |
a2879634 | 97 | clks_rem = do_div(clks, UL_5POW12); |
905acde2 | 98 | clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12; |
e820a131 KM |
99 | clks >>= 13; |
100 | ||
905acde2 YS |
101 | /* If we had a remainder greater than the 1ps error, then round up */ |
102 | if (clks_rem > data_rate) | |
58e5e9af | 103 | clks++; |
58e5e9af | 104 | |
e820a131 | 105 | /* Clamp to the maximum representable value */ |
a2879634 KM |
106 | if (clks > ULL_8FS) |
107 | clks = ULL_8FS; | |
58e5e9af KG |
108 | return (unsigned int) clks; |
109 | } | |
110 | ||
03e664d8 | 111 | unsigned int mclk_to_picos(const unsigned int ctrl_num, unsigned int mclk) |
58e5e9af | 112 | { |
03e664d8 | 113 | return get_memory_clk_period_ps(ctrl_num) * mclk; |
58e5e9af KG |
114 | } |
115 | ||
9ac4ffbd | 116 | #ifdef CONFIG_PPC |
58e5e9af KG |
117 | void |
118 | __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, | |
a4c66509 | 119 | unsigned int law_memctl, |
58e5e9af KG |
120 | unsigned int ctrl_num) |
121 | { | |
e7563aff KG |
122 | unsigned long long base = memctl_common_params->base_address; |
123 | unsigned long long size = memctl_common_params->total_mem; | |
124 | ||
58e5e9af KG |
125 | /* |
126 | * If no DIMMs on this controller, do not proceed any further. | |
127 | */ | |
128 | if (!memctl_common_params->ndimms_present) { | |
129 | return; | |
130 | } | |
131 | ||
e7563aff KG |
132 | #if !defined(CONFIG_PHYS_64BIT) |
133 | if (base >= CONFIG_MAX_MEM_MAPPED) | |
134 | return; | |
135 | if ((base + size) >= CONFIG_MAX_MEM_MAPPED) | |
136 | size = CONFIG_MAX_MEM_MAPPED - base; | |
137 | #endif | |
a4c66509 YS |
138 | if (set_ddr_laws(base, size, law_memctl) < 0) { |
139 | printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num, | |
140 | law_memctl); | |
141 | return ; | |
58e5e9af | 142 | } |
a4c66509 YS |
143 | debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n", |
144 | base, size, law_memctl); | |
58e5e9af KG |
145 | } |
146 | ||
147 | __attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void | |
148 | fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, | |
149 | unsigned int memctl_interleaved, | |
150 | unsigned int ctrl_num); | |
9ac4ffbd | 151 | #endif |
d9c147f3 | 152 | |
a4c66509 YS |
153 | void fsl_ddr_set_intl3r(const unsigned int granule_size) |
154 | { | |
155 | #ifdef CONFIG_E6500 | |
156 | u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); | |
157 | *mcintl3r = 0x80000000 | (granule_size & 0x1f); | |
158 | debug("Enable MCINTL3R with granule size 0x%x\n", granule_size); | |
159 | #endif | |
160 | } | |
161 | ||
eb539412 YS |
162 | u32 fsl_ddr_get_intl3r(void) |
163 | { | |
164 | u32 val = 0; | |
165 | #ifdef CONFIG_E6500 | |
166 | u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); | |
167 | val = *mcintl3r; | |
168 | #endif | |
169 | return val; | |
170 | } | |
171 | ||
1d71efbb | 172 | void print_ddr_info(unsigned int start_ctrl) |
d9c147f3 | 173 | { |
9a17eb5b YS |
174 | struct ccsr_ddr __iomem *ddr = |
175 | (struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR); | |
e76cd5d4 | 176 | |
a4c66509 YS |
177 | #if defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3) |
178 | u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); | |
179 | #endif | |
d9c147f3 | 180 | #if (CONFIG_NUM_DDR_CONTROLLERS > 1) |
4e5b1bd0 | 181 | uint32_t cs0_config = ddr_in32(&ddr->cs0_config); |
d9c147f3 | 182 | #endif |
4e5b1bd0 | 183 | uint32_t sdram_cfg = ddr_in32(&ddr->sdram_cfg); |
d9c147f3 PT |
184 | int cas_lat; |
185 | ||
123922b1 | 186 | #if CONFIG_NUM_DDR_CONTROLLERS >= 2 |
1d71efbb YS |
187 | if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) || |
188 | (start_ctrl == 1)) { | |
5614e71b | 189 | ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR; |
4e5b1bd0 | 190 | sdram_cfg = ddr_in32(&ddr->sdram_cfg); |
123922b1 YS |
191 | } |
192 | #endif | |
193 | #if CONFIG_NUM_DDR_CONTROLLERS >= 3 | |
1d71efbb YS |
194 | if ((!(sdram_cfg & SDRAM_CFG_MEM_EN)) || |
195 | (start_ctrl == 2)) { | |
5614e71b | 196 | ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR; |
4e5b1bd0 | 197 | sdram_cfg = ddr_in32(&ddr->sdram_cfg); |
123922b1 YS |
198 | } |
199 | #endif | |
1d71efbb YS |
200 | |
201 | if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) { | |
202 | puts(" (DDR not enabled)\n"); | |
203 | return; | |
204 | } | |
205 | ||
d9c147f3 PT |
206 | puts(" (DDR"); |
207 | switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >> | |
208 | SDRAM_CFG_SDRAM_TYPE_SHIFT) { | |
209 | case SDRAM_TYPE_DDR1: | |
210 | puts("1"); | |
211 | break; | |
212 | case SDRAM_TYPE_DDR2: | |
213 | puts("2"); | |
214 | break; | |
215 | case SDRAM_TYPE_DDR3: | |
216 | puts("3"); | |
217 | break; | |
34e026f9 YS |
218 | case SDRAM_TYPE_DDR4: |
219 | puts("4"); | |
220 | break; | |
d9c147f3 PT |
221 | default: |
222 | puts("?"); | |
223 | break; | |
224 | } | |
225 | ||
226 | if (sdram_cfg & SDRAM_CFG_32_BE) | |
227 | puts(", 32-bit"); | |
0b3b1766 PA |
228 | else if (sdram_cfg & SDRAM_CFG_16_BE) |
229 | puts(", 16-bit"); | |
d9c147f3 PT |
230 | else |
231 | puts(", 64-bit"); | |
232 | ||
233 | /* Calculate CAS latency based on timing cfg values */ | |
34e026f9 | 234 | cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf); |
66869f95 | 235 | if (fsl_ddr_get_version(0) <= 0x40400) |
34e026f9 YS |
236 | cas_lat += 1; |
237 | else | |
238 | cas_lat += 2; | |
239 | cas_lat += ((ddr_in32(&ddr->timing_cfg_3) >> 12) & 3) << 4; | |
d9c147f3 PT |
240 | printf(", CL=%d", cas_lat >> 1); |
241 | if (cas_lat & 0x1) | |
242 | puts(".5"); | |
243 | ||
244 | if (sdram_cfg & SDRAM_CFG_ECC_EN) | |
245 | puts(", ECC on)"); | |
246 | else | |
247 | puts(", ECC off)"); | |
248 | ||
a4c66509 YS |
249 | #if (CONFIG_NUM_DDR_CONTROLLERS == 3) |
250 | #ifdef CONFIG_E6500 | |
251 | if (*mcintl3r & 0x80000000) { | |
252 | puts("\n"); | |
253 | puts(" DDR Controller Interleaving Mode: "); | |
254 | switch (*mcintl3r & 0x1f) { | |
255 | case FSL_DDR_3WAY_1KB_INTERLEAVING: | |
256 | puts("3-way 1KB"); | |
257 | break; | |
258 | case FSL_DDR_3WAY_4KB_INTERLEAVING: | |
259 | puts("3-way 4KB"); | |
260 | break; | |
261 | case FSL_DDR_3WAY_8KB_INTERLEAVING: | |
262 | puts("3-way 8KB"); | |
263 | break; | |
264 | default: | |
265 | puts("3-way UNKNOWN"); | |
266 | break; | |
267 | } | |
268 | } | |
269 | #endif | |
270 | #endif | |
271 | #if (CONFIG_NUM_DDR_CONTROLLERS >= 2) | |
1d71efbb | 272 | if ((cs0_config & 0x20000000) && (start_ctrl == 0)) { |
d9c147f3 PT |
273 | puts("\n"); |
274 | puts(" DDR Controller Interleaving Mode: "); | |
275 | ||
276 | switch ((cs0_config >> 24) & 0xf) { | |
6b1e1254 YS |
277 | case FSL_DDR_256B_INTERLEAVING: |
278 | puts("256B"); | |
279 | break; | |
d9c147f3 PT |
280 | case FSL_DDR_CACHE_LINE_INTERLEAVING: |
281 | puts("cache line"); | |
282 | break; | |
283 | case FSL_DDR_PAGE_INTERLEAVING: | |
284 | puts("page"); | |
285 | break; | |
286 | case FSL_DDR_BANK_INTERLEAVING: | |
287 | puts("bank"); | |
288 | break; | |
289 | case FSL_DDR_SUPERBANK_INTERLEAVING: | |
290 | puts("super-bank"); | |
291 | break; | |
292 | default: | |
293 | puts("invalid"); | |
294 | break; | |
295 | } | |
296 | } | |
297 | #endif | |
298 | ||
299 | if ((sdram_cfg >> 8) & 0x7f) { | |
300 | puts("\n"); | |
301 | puts(" DDR Chip-Select Interleaving Mode: "); | |
302 | switch(sdram_cfg >> 8 & 0x7f) { | |
303 | case FSL_DDR_CS0_CS1_CS2_CS3: | |
304 | puts("CS0+CS1+CS2+CS3"); | |
305 | break; | |
306 | case FSL_DDR_CS0_CS1: | |
307 | puts("CS0+CS1"); | |
308 | break; | |
309 | case FSL_DDR_CS2_CS3: | |
310 | puts("CS2+CS3"); | |
311 | break; | |
312 | case FSL_DDR_CS0_CS1_AND_CS2_CS3: | |
313 | puts("CS0+CS1 and CS2+CS3"); | |
314 | break; | |
315 | default: | |
316 | puts("invalid"); | |
317 | break; | |
318 | } | |
319 | } | |
320 | } | |
1d71efbb YS |
321 | |
322 | void __weak detail_board_ddr_info(void) | |
323 | { | |
324 | print_ddr_info(0); | |
325 | } | |
326 | ||
327 | void board_add_ram_info(int use_default) | |
328 | { | |
329 | detail_board_ddr_info(); | |
330 | } | |
e32d59a2 YS |
331 | |
332 | #ifdef CONFIG_FSL_DDR_SYNC_REFRESH | |
333 | #define DDRC_DEBUG20_INIT_DONE 0x80000000 | |
334 | #define DDRC_DEBUG2_RF 0x00000040 | |
335 | void fsl_ddr_sync_memctl_refresh(unsigned int first_ctrl, | |
336 | unsigned int last_ctrl) | |
337 | { | |
338 | unsigned int i; | |
339 | u32 ddrc_debug20; | |
340 | u32 ddrc_debug2[CONFIG_NUM_DDR_CONTROLLERS] = {}; | |
341 | u32 *ddrc_debug2_p[CONFIG_NUM_DDR_CONTROLLERS] = {}; | |
342 | struct ccsr_ddr __iomem *ddr; | |
343 | ||
344 | for (i = first_ctrl; i <= last_ctrl; i++) { | |
345 | switch (i) { | |
346 | case 0: | |
347 | ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; | |
348 | break; | |
349 | #if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) | |
350 | case 1: | |
351 | ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; | |
352 | break; | |
353 | #endif | |
354 | #if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) | |
355 | case 2: | |
356 | ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; | |
357 | break; | |
358 | #endif | |
359 | #if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) | |
360 | case 3: | |
361 | ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; | |
362 | break; | |
363 | #endif | |
364 | default: | |
365 | printf("%s unexpected ctrl = %u\n", __func__, i); | |
366 | return; | |
367 | } | |
368 | ddrc_debug20 = ddr_in32(&ddr->debug[19]); | |
369 | ddrc_debug2_p[i] = &ddr->debug[1]; | |
370 | while (!(ddrc_debug20 & DDRC_DEBUG20_INIT_DONE)) { | |
371 | /* keep polling until DDRC init is done */ | |
372 | udelay(100); | |
373 | ddrc_debug20 = ddr_in32(&ddr->debug[19]); | |
374 | } | |
375 | ddrc_debug2[i] = ddr_in32(&ddr->debug[1]) | DDRC_DEBUG2_RF; | |
376 | } | |
377 | /* | |
378 | * Sync refresh | |
379 | * This is put together to make sure the refresh reqeusts are sent | |
380 | * closely to each other. | |
381 | */ | |
382 | for (i = first_ctrl; i <= last_ctrl; i++) | |
383 | ddr_out32(ddrc_debug2_p[i], ddrc_debug2[i]); | |
384 | } | |
385 | #endif /* CONFIG_FSL_DDR_SYNC_REFRESH */ | |
61bd2f75 YS |
386 | |
387 | void remove_unused_controllers(fsl_ddr_info_t *info) | |
388 | { | |
389 | #ifdef CONFIG_FSL_LSCH3 | |
390 | int i; | |
391 | u64 nodeid; | |
392 | void *hnf_sam_ctrl = (void *)(CCI_HN_F_0_BASE + CCN_HN_F_SAM_CTL); | |
393 | bool ddr0_used = false; | |
394 | bool ddr1_used = false; | |
395 | ||
396 | for (i = 0; i < 8; i++) { | |
397 | nodeid = in_le64(hnf_sam_ctrl) & CCN_HN_F_SAM_NODEID_MASK; | |
398 | if (nodeid == CCN_HN_F_SAM_NODEID_DDR0) { | |
399 | ddr0_used = true; | |
400 | } else if (nodeid == CCN_HN_F_SAM_NODEID_DDR1) { | |
401 | ddr1_used = true; | |
402 | } else { | |
403 | printf("Unknown nodeid in HN-F SAM control: 0x%llx\n", | |
404 | nodeid); | |
405 | } | |
406 | hnf_sam_ctrl += (CCI_HN_F_1_BASE - CCI_HN_F_0_BASE); | |
407 | } | |
408 | if (!ddr0_used && !ddr1_used) { | |
409 | printf("Invalid configuration in HN-F SAM control\n"); | |
410 | return; | |
411 | } | |
412 | ||
413 | if (!ddr0_used && info->first_ctrl == 0) { | |
414 | info->first_ctrl = 1; | |
415 | info->num_ctrls = 1; | |
416 | debug("First DDR controller disabled\n"); | |
417 | return; | |
418 | } | |
419 | ||
420 | if (!ddr1_used && info->first_ctrl + info->num_ctrls > 1) { | |
421 | info->num_ctrls = 1; | |
422 | debug("Second DDR controller disabled\n"); | |
423 | } | |
424 | #endif | |
425 | } |