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